# Suno Android

---

## 🚀 Getting Started

### Installation

1. Clone the repository:

```bash
git clone git@github.com:suno-ai/app-android.git
```

2. Install dependencies:

```bash
./INSTALL
```

This should include setting up the Java and Ruby environment, as well as development tools such as:

- ktlint
- detekt
- pre-commit hooks for running these tools on every commit.


3. Import Project into Android Studio:
4. Perform a Gradle Sync by clicking on the elephant with arrow in the upper right hand corner
5. Compile the app by clicking the green arrow in the upper middle right or executing
   `control + r`
6. Hopefully it was that easy!

---

### IDE Setup

It's recommended to install Android Studio via **JetBrains Toolbox** for the best development
experience:

1. **Download JetBrains Toolbox
   **: [https://www.jetbrains.com/toolbox-app/](https://www.jetbrains.com/toolbox-app/)

2. **Install Android Studio**: Use Toolbox to install **Android Studio Meerkat | 2024.3.1**

**Benefits of using JetBrains Toolbox:**

- **Version management**: Easy switching between Android Studio versions
- **Centralized management**: All JetBrains tools in one place
- **Rollback capability**: Quick rollback to previous versions if needed
- **Project management**: Direct access to recent projects across all IDEs

#### Recommended plugins

`ktlint` is a fast linter we're using for basic syntax and style guide checks. Once it's optimized,
it can be used as a pre-commit script to quickly lint your code changes.

`detekt` is a code analysis tool to help with code smells and general codebase health.

It's recommended to use the plugins for both of these for Android Studio.
https://plugins.jetbrains.com/plugin/15057-ktlint
https://plugins.jetbrains.com/plugin/10761-detekt

It's recommended to set your ktlint plugin settings to 'Distract free' - this will set ktlint to
format your code on save.
![ktlint_distraction_free.png](docs/ktlint_distraction_free.png)

#### Running the app

- The build variant that the app compiles and deploys by defaults is prodDebug.
  - You won't be able to login via OAuth with a debug variant of the build unless app links is enabled
    first (for debug builds it defaults to off). You'll need to go into the app settings in your
    emulator or device and configure that to be toggled on.

1. Click on the hammer with the square icon along the left edge of the IDE tool pane
2. In the :app module row, and under the active build variant column, click on prodDebug
3. From there you can choose staffDebug. This will also execute a gradle script to change all
   submodule variants to staffDebug as well
4. You should be able to compile the staff version of the app now

![build_variants.png](docs/build_variants.png)

#### GOTCHA!

> Google accounts on emulators will NOT WORK unless you have sufficient security on your device -
> then you can verify your account and log in with Google. **Add a passcode to your device and
> you'll
> be able to log in via Google.**

---

### Architecture

- The app is loosely multi-modular, with an intent to further modularize and organize things in the
  future. It's up for debate how far we'll want to modularize, but it would be nice to avoid a
  thousand module setup that can sometimes be seen in big tech companies. Ideally strive for 10-30
  modules, depending on feature set.
- Utility functions and extensions that would make sense to be accessible in any module are in
  `common-core-utils`. When creating a new submodule, `common-core-utils` will probably be one of
  the first submodules to implement
- UI components are in our common-ui module
- :common-data depends on both :common-networking and :common-db. It is the eventual intention to
  stop injecting the network services directly and inject repos through the :common-data layer
- Started off with an MVVM architecture for speed of development. Would possibly like to migrate
  over to MVI but would want to have a larger discussion with the team about this

---

### Interesting things about the app

# Authentication

- Our authentication relies upon a 3rd party service, Clerk. Although Clerk has a beta iOS SDK and a
  fully supported web SDK, Clerk does not have an Android SDK... nor do they plan to make one at
  anytime in the near future (as of April 2025).
  Clerk relies on a 2 tier rotating token mechanism. There is a "long-lived token" that the app
  caches and uses to request a rotating short-lived JWT token that expires _every minute._ This
  rotating short-lived JWT token is what gets used to make authenticated API requests to our own
  API.
  When making _any_ API request against the clerk service, the "long-lived token" can also be
  expired and rotated out at _anytime_. This long lived token must be rotated out and be used to
  make subsequent calls to fetch the short lived JWT token.
- You can read more about their philosophy
  behind [stateless authentication and how it works here](https://clerk.com/docs/how-clerk-works/overview#stateless-authentication)

# Media Playback

- Suno is a full fledged media app that supports background playback. Special care should be taken
  to ensure appropriate bi-directional syncing with the app state and binded OS level foreground
  service state.

# Productivity

- In Android Studio, configure your IDE to optimize imports on the fly.

    - Access your IDE settings, by pressing `⌘,`
    - Navigate to Editor > General > Auto Import
    - Under the kotlin section, ensure that both "Add unambiguous imports on the fly" and "Optimize
      imports on the fly" are both checked on.

- Android Studio supports code snippets, called "live templates," so that you can autogenerate code
  with a few key presses:
    - To generate default composable elements with previews, copy the live
      template [here](/docs/templates/composables-with-previews/composable-with-preview.md)
    - To generate default composable screens with viewModels and boilerplate code, copy the live
      template from [here](/docs/templates/screens/screens.md)

## Claude PR Assistant

- To generate a PR description using Claude, set it to an empty value.
- To request a PR review from Claude, tag or mention @suno-ai/claude-code-review team.
- To perform a custom action using Claude, mention @claude in comment thread.

## CI/CD

### Linting

Our linter can sometimes be annoying and we're working on it. Feel free to regenerate either the detekt baseline or ktlint baseline if it's getting too much in your way... There's also a shell script you can run for both:

- First give permission `chmod +x ./tools/baseline.sh`
- Then execute when needed `./tools/baseline.sh`

### Authentication

CI workflows that create PRs to push commits should use the `SUNO_CI_BOT_GH_TOKEN` secret instead of
the default Github token.

> **IMPORTANT**: The token is owned by [suno-ai-bot](https://github.com/suno-ci-bot) and is only
> valid for _1 year_. If you need to refresh the expired token, please post in **#pod-core** on
> Slack
> and ask for password to ci.cd@suno.com bot account
