Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions docs/main/android/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,59 @@ Also, if you are migrating from Capacitor 1 or 2, make sure you enabled the [aut

If still getting the "Plugin not implemented" error, make sure you are not using service workers, that prevents Capacitor's and Plugins code from injecting. Or if you want to use them, you can use [this workaround](https://github.com/ionic-team/capacitor/issues/1655#issuecomment-579229390) for making the injection work.

## Using Proguard
## Using R8

ProGuard is a tool used to shrink, obfuscate, and reduce the size of your app. It is enabled by setting the `minifyEnabled` option in `build.gradle` to `true`. This process can sometimes lead to issues in Capacitor when using a plugin or some custom native code that relies on its code being being readable at run time, such as code reflection. ProGuard scans code to try and optimize and shrink the size of an app and sometimes this process can remove classes or methods that are important for the functionality of a plugin.
R8 shrinks, optimizes and obfuscates your app's code when `minifyEnabled` is `true` in the release block of `app/build.gradle`. It's on by default in Capacitor 9 apps. To turn it off, set `minifyEnabled false`.

As of Capacitor v3.2.3 there are ProGuard rules included in Capacitor that cover the core functionality of Capacitor plugins, permissions, and activity results. If you are using an earlier version of Capacitor than v3.2.3, add [the following rules](https://github.com/ionic-team/capacitor/blob/main/android/capacitor/proguard-rules.pro) to your Android project's `proguard-rules.pro` file. Those rules should resolve problems with any of the core Capacitor features and core plugins.
Capacitor and the official plugins ship the rules they need, so most apps don't need rules of their own. R8 only runs in release builds, so test a release build before publishing.

If you still encounter any issues after adding those rules, try to identify the source plugin or native code and add a rule to cover the specific plugin code, for example:
### When something fails only in release

R8 removes or renames code it can't see being used, such as classes looked up by name, code called from native code, and Gson models without `@SerializedName`. Find the class in the error and add a keep rule for it to `app/proguard-rules.pro`:

```
-keep class com.mythirdpartyplugin.** { *; }
-keep class com.example.MyModel { <fields>; }
```

If you are certain a Capacitor plugin is causing the ProGuard issue the following ProGuard rule will cover any plugin class code, if you don't mind all plugins being exempt from ProGuard processing:
Keep the rule as narrow as you can, since keeping a whole package stops R8 from optimizing all of it. If the class comes from a plugin, report it to the plugin's author so the plugin can ship the rule.

If the release build fails with "Missing classes", add the rules R8 lists in `app/build/outputs/mapping/release/missing_rules.txt`.

### Libraries with old keep rules

AGP 9 no longer keeps a constructor just because its class is kept. Older versions of these libraries relied on that, so they fail at runtime under R8. If your app's own dependencies bring one of them, upgrade it or add its rule to `app/proguard-rules.pro`:

| Library | Fixed in | Rule |
| :------ | :------- | :--- |
| Room | 2.7 | `-keep class * extends androidx.room.RoomDatabase { <init>(); }` |
| WorkManager | 2.10 | `-keepclassmembers class * extends androidx.work.InputMerger { <init>(); }` |
| firebase-components, used by Firebase and ML Kit | 18.0.1 | `-keep class * implements com.google.firebase.components.ComponentRegistrar { <init>(); }` |

If another library fails the same way, copy its class-only keep rule into `app/proguard-rules.pro` and add `{ <init>(); }` to it.

### Stack traces

R8 writes the map of renamed classes and methods to `app/build/outputs/mapping/release/mapping.txt` and adds it to your AAB, where Google Play reads it. The Crashlytics Gradle plugin uploads it too. To decode a stack trace yourself, use [retrace](https://developer.android.com/tools/retrace).

### Resource shrinking

`shrinkResources` stays off by default. Google Play's code optimization scores only measure your app's code, so resource shrinking barely changes them, though Play Console lists it as off. If you turn it on, keep the resources your app only reads by name, such as notification icons and sounds named in `capacitor.config.json`, with a file like `app/src/main/res/raw/keep.xml`:

```xml
<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@drawable/ic_stat_notify" />
```
-keep public class * extends com.getcapacitor.Plugin

### Capacitor 8

Capacitor 8 apps have R8 off by default. To turn it on, use Capacitor 8.5.4 or later and also switch to `proguard-android-optimize.txt`, since `proguard-android.txt` turns off R8's optimizations:

```diff
buildTypes {
release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
```
18 changes: 18 additions & 0 deletions docs/main/updating/9-0.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ Whichever path you take, finish with the [iOS verification checklist](#verify-th

Capacitor 9 also removes the Java APIs that were deprecated in previous major versions, most of them used by plugin authors — see [Breaking changes in code](/main/updating/plugins/9-0.md#android). If your app has custom native code, check that list too.

Release builds now run R8 by default, which can break code that R8 can't see being used. See [Turn on R8 in release builds](#turn-on-r8-in-release-builds) below.

## Breaking changes in @capacitor/ios

Capacitor 9 boots iOS apps from a SwiftUI `App` struct instead of a UIKit `AppDelegate`. Your app project gains `App.swift` and `CapacitorView.swift`, the `AppDelegate` is demoted to a `@UIApplicationDelegateAdaptor`, your `SceneDelegate` is emptied out, and `Main.storyboard` is deleted. Every app needs this change, including apps already on 8.5 — see [Adopt the SwiftUI entry point](#adopt-the-swiftui-entry-point) below.
Expand Down Expand Up @@ -429,6 +431,22 @@ buildTypes {
}
```

### Turn on R8 in release builds

New Capacitor 9 apps build their release with R8, which shrinks, optimizes and obfuscates the app's code, and `npx cap migrate` turns it on in existing apps. Google Play will [require code optimization](https://support.google.com/googleplay/android-developer/answer/17492799) for larger apps from February 2027. If `npx cap migrate` warns that it couldn't set `minifyEnabled`, set it in the release block of `app/build.gradle`:

```diff
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
```

R8 only runs in release builds, so test a release build of your app after updating. If something fails only in release, see [Using R8](/main/android/troubleshooting.md#using-r8). To keep R8 off, set `minifyEnabled false`.

### Declare dependency versions in your app's build.gradle

Your `app/build.gradle` references version variables that are declared in the root project's `variables.gradle`, and relies on Gradle walking up the project hierarchy to resolve them. That implicit lookup is deprecated in Gradle 9.6 and becomes an error in Gradle 10, so declare them explicitly at the top of the file:
Expand Down
26 changes: 26 additions & 0 deletions docs/main/updating/plugins/9-0.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,32 @@ buildTypes {
}
```

### Check your plugin with R8

Capacitor 9 apps run R8 in release builds by default, so plugin code that R8 can't see being used breaks in release. Check your plugin for:

- Classes or methods looked up by name, or created or called from native code (JNI)
- Gson models without `@SerializedName`, Gson below 2.11, or library classes like `kotlin.Pair` serialized to JSON
- Dependencies that reference classes your plugin doesn't include, which fail the app's release build with "Missing classes". Add the `-dontwarn` lines R8 lists in the app's `build/outputs/mapping/release/missing_rules.txt`.
- Room below 2.7, WorkManager below 2.10, or firebase-components below 18.0.1, which need the rules in [Libraries with old keep rules](/main/android/troubleshooting.md#libraries-with-old-keep-rules)

Put the rules in `android/proguard-rules.pro` and ship that file to apps. `@capacitor/plugin-migration-v8-to-v9` does this for you when the file exists:

```diff
// android/build.gradle
defaultConfig {
+ consumerProguardFiles "proguard-rules.pro"
}
```

```diff
// package.json
"files": [
+ "android/proguard-rules.pro",
```

Keep the rules narrow, since they apply to every app that uses your plugin, and leave out global options like `-dontobfuscate`, which fail the app's build under AGP 9. To test, build your example app's release with `minifyEnabled true`, call each plugin method, and check it behaves as in a debug build.

### Remove the standalone Kotlin plugin

AGP 9 bundles the Kotlin Gradle Plugin natively (Kotlin `2.2.10`) instead of requiring it to be applied separately. If your plugin still applies `kotlin-android` (or `org.jetbrains.kotlin.android`) and declares its own `kotlin_version`/`kotlin-stdlib`/`kotlin-gradle-plugin`, remove them, otherwise you'll hit a duplicate-plugin build failure:
Expand Down
13 changes: 13 additions & 0 deletions docs/plugins/cordova.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ Capacitor does not support Cordova install variables, auto configuration, or hoo

Consult the [iOS](/main/ios/configuration.md) and [Android](/main/android/configuration.md) configuration guides for info on how to configure each platform.

### R8 rules

Capacitor already keeps Cordova plugin classes from R8. If a plugin needs more rules, for example for a class it loads by name, its Gradle file (the `<framework custom="true" type="gradleReference" />` in `plugin.xml`) has to write them, since Cordova apps only get that file. Write them outside the build folder, so `clean` doesn't delete them before R8 runs:

```groovy
def rules = new File(rootDir, '.gradle/my-plugin-rules.pro')
rules.parentFile.mkdirs()
rules.text = '-keep class com.example.LoadedByName { <init>(); }\n'
android.buildTypes.release.proguardFile(rules)
```

This works in both Capacitor and Cordova apps.

### Known Incompatible Plugins

If a plugin is known to conflict or cause build issues, it will be skipped when running `npx cap sync`.
Expand Down