---
title: "Code Push for Android add-to-app"
description: "Use Code Push in an add-to-app scenario with an Android app"
---

This guide explains how to use Shorebird in an Android add-to-app scenario (that is, your app embeds Flutter UI in non-Flutter UI). If you are new to this pattern, see the [Add Flutter to an existing app](/flutter-concepts/add-to-app/) Flutter Concepts article first.

Note

If your app is a pure Flutter app, follow the [standard Code Push guide](/code-push/initialize) instead.

## Prerequisites

This guide assumes you already have an Android app and a Flutter module. The Android app will be named `AddToAppDemo` (in the sample’s `AndroidAddToAppDemo` directory) and the Flutter module will be named `my_flutter_module`.

This guide also assumes that you have created a Shorebird account. If you have not, see the [Code Push guide](/code-push/initialize) for instructions.

The reference code for this guide is available at <https://github.com/shorebirdtech/samples/tree/main/add_to_app>.

Note

For releases and patches, Shorebird supports only the prebuilt AAR method of adding Flutter to a native Android app (see “Depend on the Android Archive (AAR)” in the [official integration docs](https://docs.flutter.dev/add-to-app/android/project-setup#depend-on-the-android-archive-aar)). You can depend on the module’s source code (the `include_flutter.groovy` setup) during development, but switch the host app to the AAR from `shorebird release aar` before you release, and patch it with `shorebird patch aar`. There is an open issue to support source dependencies ([link](https://github.com/shorebirdtech/shorebird/issues/653)).

## Add Shorebird to your Flutter module

First, run `shorebird init` in your Flutter module:

```
shorebird init
```

## Create a Shorebird release

Create a Shorebird release for your Flutter module:

```
shorebird release aar --release-version 1.2.3+1
```

The `release-version` parameter needs to match the version of the Android app that uses this module (i.e., `versionName+versionCode` from the app’s `app/build.gradle` file).

Note

Because Shorebird only works with release builds, this will only produce a release version of your archive. This is similar to running `flutter build aar --no-debug --no-profile`.

Note

This command creates an `aar` with a build number of `1.0`. As with the `flutter build aar` command, you may optionally provide a different build number using the `--build-number` argument, although this is not necessary. The build number is used to identify the Flutter module in your app’s `build.gradle` file, as you can see [below](#update-your-android-app-to-use-this-version-of-the-flutter-module).

Shorebird does not use the build number, but **it should remain consistent between a release and patches to that release**.

## Update your Android app to use the `download.shorebird.dev` Maven repository

In `settings.gradle.kts` (or `settings.gradle`):

* Kotlin DSL

  ```
  dependencyResolutionManagement {
      repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
      repositories {
          google()
          mavenCentral()
  +        maven {
  +            // This is a relative path from this settings.gradle.kts file to
  +            // the my_flutter_module/release directory.
  +            url = uri("../my_flutter_module/release")
  +        }
  +        maven {
  -            url = uri("https://storage.googleapis.com/download.flutter.io")
  +            url = uri("https://download.shorebird.dev/download.flutter.io")
  +        }
      }
  }
  ```

* Groovy DSL

  ```
  dependencyResolutionManagement {
      repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
      repositories {
          google()
          mavenCentral()
  +        maven {
  +           // This is a relative path from this settings.gradle file to the
  +           // my_flutter_module/release directory.
  +           url '../my_flutter_module/release'
  +       }
  +       maven {
  -           url 'https://storage.googleapis.com/download.flutter.io'
  +           url 'https://download.shorebird.dev/download.flutter.io'
  +      }
      }
  }
  ```

Note

Even though <https://storage.googleapis.com/download.flutter.io> is replaced with <https://download.shorebird.dev/download.flutter.io>, any Flutter dependencies that are not unique to Shorebird will still be downloaded from <https://storage.googleapis.com/download.flutter.io>. This will only work for versions of Flutter that Shorebird supports.

## Update your Android app to use this version of the Flutter module

In `app/build.gradle.kts` (or `app/build.gradle`), add the following:

* Kotlin DSL

  ```
  buildTypes {
      getByName("release") {
          // ...
  +        // libapp.so in the Flutter module's AAR is already stripped (by the Dart
  +        // compiler before Flutter 3.44, by the module's own Android Gradle Plugin
  +        // build from 3.44 on). Running llvm-strip on it again in this app can
  +        // change its bytes, which confuses Shorebird tools. This line tells Gradle
  +        // to skip that step for libapp.so, so the libapp.so Shorebird recorded is
  +        // byte-identical to the one in your APK/AAB.
  +        packaging.jniLibs.keepDebugSymbols.add("**/libapp.so")
          // ...
      }
  }

  dependencies {
      // ...
  +    releaseImplementation("com.example.my_flutter_module:flutter_release:1.0")
      // ...
  }
  ```

* Groovy DSL

  ```
  buildTypes {
      release {
          // ...
  +        // libapp.so in the Flutter module's AAR is already stripped (by the Dart
  +        // compiler before Flutter 3.44, by the module's own Android Gradle Plugin
  +        // build from 3.44 on). Running llvm-strip on it again in this app can
  +        // change its bytes, which confuses Shorebird tools. This line tells Gradle
  +        // to skip that step for libapp.so, so the libapp.so Shorebird recorded is
  +        // byte-identical to the one in your APK/AAB.
  +        packaging.jniLibs.keepDebugSymbols.add("**/libapp.so")
          // ...
      }
  }

  dependencies {
      // ...
  +    releaseImplementation 'com.example.my_flutter_module:flutter_release:1.0'
      // ...
  }
  ```

Keep the `keepDebugSymbols` line on every Flutter version. The [Flutter 3.44 advice to remove it](/code-push/troubleshooting#libappsosym-or-libappsodbg-not-present-warning-on-android) is for a Flutter app’s `android/app/build.gradle`, not for your host app’s `app/build.gradle`.

## Verify that your app runs

In Android Studio, update the active build variant to release and run your app. Your app should work as before with no differences.

To set the active build variant to release, click on the “Build Variants” tab in the lower left corner of Android Studio. Then select “release” from the “Active Build Variant” dropdown.

![Android Studio build variant set to release](/_astro/hybrid_android_screenshot.BaEBo9fG_ZItjf.webp)

Attempting to build with a non-release build variant will not be able to resolve Flutter symbols in your app.

## Submit your app to the Play Store

This step isn’t covered in detail here, but this is where you would submit your app to the Play Store. For Code Push to work, it is important that you submit *with the same `aar` generated by the release command above*.

## Verify that Shorebird is working with a patch

Make an edit to the code in your Flutter module. Then run:

```
shorebird patch aar --release-version 1.2.3+1 --track=stable
```

Note

If you provided a build number to the `shorebird release aar` command using the `--build-number` argument, you must also provide that same build number to the `shorebird patch aar` command.

As with the `release` command, the release version should be the version of the Android app that uses this module.

Now relaunch the app, navigate to the Flutter screen, and verify that the patch is recognized and applied. In logcat, you should see output like the following:

```
[INFO:shorebird.cc(109)] Shorebird updater: no active patch.
[INFO:shorebird.cc(113)] Starting Shorebird update
updater::network: [shorebird] Sending patch check request: app_id: baad0583-6810-44a7-9034-6aadb8127f29, channel: stable, release_version: 1.0.0+8, platform: android, arch: aarch64, current_patch_number: None
updater::updater: [shorebird] Patch 1 successfully downloaded. It will be launched when the app next restarts.
updater::updater: [shorebird] Update thread finished with status: Update installed
```

## Release and patch the module from CI

In CI, the module and the host app are usually built by different jobs. Keep the module’s `release` directory from the job that released it, and build the host app you ship from that directory:

1. The release job runs `shorebird release aar --release-version 1.2.3+1` in the module and keeps the `release` directory it writes, for example as a build artifact.
2. The host app’s store build reads the module from that `release` directory, through the `maven` repository in `settings.gradle` above. Don’t rebuild the module for the store build: patches install only on the `aar` that `shorebird release aar` built.
3. A patch job runs `shorebird patch aar --release-version 1.2.3+1 --track=stable` in the module, with the same `--build-number` as the release if you passed one. It doesn’t need the `release` directory; Shorebird downloads what it needs from the release.

The job needs `SHOREBIRD_TOKEN`; see the [CI guides](/code-push/ci/generic/). With GitHub Actions, the Shorebird actions take `platform: aar`. The release version goes in `args` for a release and in `release-version` for a patch:

```
- name: 🚀 Release the module
  uses: shorebirdtech/shorebird-release@v1
  with:
    flutter-version: 3.47.9
    platform: aar
    working-directory: my_flutter_module
    args: --release-version 1.2.3+1

- name: 📦 Keep the module's release directory
  uses: actions/upload-artifact@v7
  with:
    name: my_flutter_module-release
    path: my_flutter_module/release
```

```
- name: 🚀 Patch the module
  uses: shorebirdtech/shorebird-patch@v1
  with:
    platform: aar
    release-version: 1.2.3+1
    track: stable
    working-directory: my_flutter_module
```

See [GitHub Integration](/code-push/ci/github/) for the rest of the workflow, including Java setup.

## Test patches before publishing them

To try a patch in a host app you build yourself before your users get it, see [Test an add-to-app patch before publishing it](/code-push/guides/add-to-app/testing-patches).

To give QA a build of your host app that gets patches before your users do, see [Give QA an add-to-app build, then promote it](/code-push/guides/add-to-app/qa-builds).

## Multiple Dart entrypoints

If your host app starts the module through more than one Dart entrypoint or engine, see [Multiple Dart entrypoints and engines](/code-push/guides/add-to-app/multiple-entrypoints).
