Skip to content

Commit 21bef15

Browse files
fix: [SDK-4511] fix Android build with Kotlin stdlib 2.2.x (#20)
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent bc7e53d commit 21bef15

81 files changed

Lines changed: 2043 additions & 27 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

android/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# OneSignal Capacitor Plugin – Android
2+
3+
Thin Capacitor wrapper around the OneSignal Android SDK. Designed to be consumed as a Capacitor sub-project under both Capacitor 7 and Capacitor 8.
4+
5+
## Kotlin / AGP toolchain
6+
7+
The plugin module declares its own `buildscript` classpath for the Android Gradle Plugin and the Kotlin Gradle Plugin. This is required because Capacitor 7's host `build.gradle` does not classpath the Kotlin Gradle Plugin for sub-projects; without our own classpath the `kotlin-android` plugin would fail to resolve.
8+
9+
Defaults live in [`gradle/libs.versions.toml`](gradle/libs.versions.toml):
10+
11+
- `kotlin = "2.2.20"` – the compiler version used to build this module. Matches the Capacitor 8 upgrade guide's recommended `kotlin_version`, and a 2.2.x compiler reads `kotlin-stdlib` bytecode from both 1.x and 2.x, which is what makes a single artifact work on Capacitor 7 hosts (Kotlin 1.9.x stdlib) and Capacitor 8 hosts (Kotlin 2.2.x stdlib).
12+
- `androidGradlePlugin = "8.7.3"` – intentionally stays below Capacitor 8's recommended 8.13.0 so plugin-only Gradle invocations still work from a freshly scaffolded Capacitor 7 project (Gradle 8.11.1). In host builds the host's AGP wins regardless.
13+
14+
Host apps that need to pin a different Kotlin compiler can do so via any standard Gradle property source — `rootProject.ext.kotlin_version` in their root `build.gradle`, `kotlin_version=…` in `gradle.properties`, or `-Pkotlin_version=…` on the command line. The plugin's buildscript block reads the value through `project.findProperty("kotlin_version")` and falls back to the catalog default.
15+
16+
## SDK levels
17+
18+
`compileSdk`, `minSdk`, and `targetSdk` default to the Capacitor 8 floors (36 / 24 / 36). Host apps override any of them by setting the matching `<name>Version` property through any Gradle property source (`rootProject.ext`, `gradle.properties`, or `-P`) — Capacitor 7 host apps that ship with `variables.gradle` defaults of 35 / 23 / 35 will continue to take precedence over the catalog defaults.
19+
20+
## Library versions
21+
22+
`androidx.appcompat`, `junit`, espresso, and the OneSignal native SDK versions also live in [`gradle/libs.versions.toml`](gradle/libs.versions.toml). `androidxAppCompatVersion` and `junitVersion` can be overridden per-project through any Gradle property source (`rootProject.ext`, `gradle.properties`, or `-P`).

android/build.gradle.kts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,23 @@ buildscript {
2424
return result ?: error("Version '$key' not found in ${catalogFile.name}")
2525
}
2626

27-
val kotlinVersion: String = if (project.hasProperty("kotlin_version")) {
28-
rootProject.extra["kotlin_version"] as String
29-
} else {
30-
fromCatalog("kotlin")
31-
}
27+
// Both AGP and Kotlin Gradle Plugin are classpathed here so the plugin
28+
// builds inside Capacitor 7 hosts, whose root build.gradle does not
29+
// provide either for sub-projects. Capacitor 8 hosts that already pin
30+
// their own kotlin_version can override via rootProject.ext.kotlin_version.
31+
//
32+
// The catalog default matches the Capacitor 8 upgrade guide's
33+
// recommended kotlin_version (2.2.20). That matters because the host
34+
// classpath can resolve kotlin-stdlib to 2.x; the 1.9 compiler can't
35+
// read 2.x metadata, which is exactly what broke 1.0.2 on Capacitor 8
36+
// (issue #18). A 2.2.x compiler reads both 1.x and 2.x stdlib bytecode,
37+
// so the plugin works under Cap 7 and Cap 8.
38+
// findProperty matches hasProperty's broad source set (extras, gradle.properties,
39+
// -P flags, ORG_GRADLE_PROJECT_* env vars). Reading rootProject.extra directly
40+
// would only see ext { ... } values and crash on the others with
41+
// UnknownPropertyException, so prefer findProperty + toString().
42+
val kotlinVersion: String =
43+
project.findProperty("kotlin_version")?.toString() ?: fromCatalog("kotlin")
3244
val androidGradlePluginVersion: String = fromCatalog("androidGradlePlugin")
3345

3446
repositories {
@@ -63,19 +75,14 @@ fun catalogVersion(key: String): String {
6375
return result ?: error("Version '$key' not found in ${toml.name}")
6476
}
6577

78+
// See the kotlin_version note in buildscript {}: findProperty honors every property
79+
// source hasProperty does (extras, gradle.properties, -P, env), and toString()
80+
// avoids the String/Int cast hazard since gradle.properties values are always String.
6681
fun propertyOrCatalog(propertyName: String, catalogKey: String): String =
67-
if (project.hasProperty(propertyName)) {
68-
rootProject.extra[propertyName] as String
69-
} else {
70-
catalogVersion(catalogKey)
71-
}
82+
project.findProperty(propertyName)?.toString() ?: catalogVersion(catalogKey)
7283

7384
fun intPropertyOrCatalog(propertyName: String, catalogKey: String): Int =
74-
if (project.hasProperty(propertyName)) {
75-
rootProject.extra[propertyName] as Int
76-
} else {
77-
catalogVersion(catalogKey).toInt()
78-
}
85+
project.findProperty(propertyName)?.toString()?.toInt() ?: catalogVersion(catalogKey).toInt()
7986

8087
val junitVersion: String = propertyOrCatalog("junitVersion", "junit")
8188
val androidxAppCompatVersion: String = propertyOrCatalog("androidxAppCompatVersion", "androidxAppCompat")
@@ -108,7 +115,7 @@ configure<com.android.build.gradle.LibraryExtension> {
108115
}
109116

110117
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
111-
kotlinOptions.jvmTarget = "17"
118+
compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
112119
}
113120

114121
repositories {

android/gradle/libs.versions.toml

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
# Version catalog for the OneSignal Capacitor Android plugin.
2-
# Defaults below can be overridden by the consuming app via gradle
3-
# properties or rootProject.extra (see android/build.gradle.kts).
42
#
5-
# compileSdk / minSdk / targetSdk / kotlin / appcompat / junit follow
6-
# Capacitor 7's required versions, not the OneSignal Android SDK's.
3+
# Host apps can override most defaults by setting the matching
4+
# rootProject.ext.<key> values; see android/build.gradle.kts for the
5+
# property-or-catalog lookup logic.
6+
#
7+
# kotlin: matches Capacitor 8's recommended kotlin_version (2.2.20, per
8+
# Capacitor 8 upgrade docs). A 2.2.x compiler reads kotlin-stdlib bytecode
9+
# from 1.x and 2.x without metadata version errors, which is what makes a
10+
# single artifact compile under both Capacitor 7 hosts (Kotlin 1.9.x
11+
# stdlib) and Capacitor 8 hosts (Kotlin 2.2.x stdlib).
12+
# androidGradlePlugin: kept at 8.7.3. Cap 8 recommends 8.13.0, but bumping
13+
# here would force Gradle 8.13+ in standalone plugin builds, which a
14+
# freshly scaffolded Cap 7 project (Gradle 8.11.1) cannot supply. In host
15+
# builds the host's AGP wins regardless.
16+
# SDK levels / library versions: bumped to Capacitor 8's recommended floors
17+
# for documentation parity. Host apps still override via rootProject.ext.
718

819
[versions]
920
androidGradlePlugin = "8.7.3"
10-
androidxAppCompat = "1.7.0"
11-
androidxEspresso = "3.6.1"
12-
androidxTestJunit = "1.2.1"
13-
compileSdk = "35"
21+
androidxAppCompat = "1.7.1"
22+
androidxEspresso = "3.7.0"
23+
androidxTestJunit = "1.3.0"
24+
compileSdk = "36"
1425
junit = "4.13.2"
15-
kotlin = "1.9.25"
16-
minSdk = "23"
26+
kotlin = "2.2.20"
27+
minSdk = "24"
1728
onesignal = "5.9.1"
18-
targetSdk = "35"
29+
targetSdk = "36"
1930

2031
[libraries]
2132
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidxAppCompat" }

examples/demo_cap7/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Angular CLI cache + intermediate TS output
2+
.angular/
3+
out-tsc/

examples/demo_cap7/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# demo-cap7
2+
3+
Minimal Capacitor 7 + Angular sample used to verify the OneSignal Capacitor plugin against the older Kotlin / AGP toolchain that Capacitor 7 ships with. Pairs with `examples/demo` (Capacitor 8, Ionic React).
4+
5+
## Stack
6+
7+
- Capacitor 7 (`@capacitor/core` `^7.4.3`)
8+
- Angular 18 standalone components, bootstrapped with `bootstrapApplication`
9+
- Angular CLI (`ng build` / `ng serve`) – no Ionic, no extra build tooling
10+
- Single root component with four buttons and a signal-backed log
11+
12+
## What the demo does
13+
14+
1. Initialize OneSignal
15+
2. Request notification permission
16+
3. Show the OneSignal user / push subscription id (paste it into the OneSignal dashboard to send a test push)
17+
4. Send Test Notification – POSTs `{ headings: 'Simple Notification', contents: 'This is a simple push notification' }` to the OneSignal REST API (`v1/notifications`) targeting the current push subscription id. Mirrors the Simple notification button in `examples/demo`; no REST API key needed since the call targets the device's own subscription id.
18+
19+
## First-time setup
20+
21+
The `android/` and `ios/` projects are committed (scaffolded via Capacitor 7's CLI, AGP 8.7.x, no root Kotlin Gradle Plugin classpath), so the only setup is dependencies and the plugin tarball.
22+
23+
```bash
24+
# from the repo root: build + pack the plugin tarball
25+
vp run build
26+
vp pm pack && mv onesignal-capacitor-plugin-*.tgz onesignal-capacitor-plugin.tgz
27+
28+
# in this folder: install deps and the local plugin tarball
29+
cd examples/demo_cap7
30+
bun install
31+
```
32+
33+
The OneSignal plugin module compiles against the Kotlin 2.2.20 compiler it ships in its own buildscript classpath, which reads both 1.x and 2.x `kotlin-stdlib` bytecode.
34+
35+
`ONESIGNAL_APP_ID` in `src/app/app.component.ts` defaults to the shared OneSignal demo app id (same one used by `examples/demo`). Swap it for your own app id before pointing the demo at a production environment.
36+
37+
## Running
38+
39+
```bash
40+
bun run build # ng build → dist/browser
41+
bunx cap sync # copy web + plugin into native projects
42+
bunx cap run android # or: bunx cap run ios
43+
```
44+
45+
The Angular CLI builder emits to `dist/browser/`; `capacitor.config.ts` points `webDir` there.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
2+
3+
# Built application files
4+
*.apk
5+
*.aar
6+
*.ap_
7+
*.aab
8+
9+
# Files for the ART/Dalvik VM
10+
*.dex
11+
12+
# Java class files
13+
*.class
14+
15+
# Generated files
16+
bin/
17+
gen/
18+
out/
19+
# Uncomment the following line in case you need and you don't have the release build type files in your app
20+
# release/
21+
22+
# Gradle files
23+
.gradle/
24+
build/
25+
26+
# Local configuration file (sdk path, etc)
27+
local.properties
28+
29+
# Proguard folder generated by Eclipse
30+
proguard/
31+
32+
# Log Files
33+
*.log
34+
35+
# Android Studio Navigation editor temp files
36+
.navigation/
37+
38+
# Android Studio captures folder
39+
captures/
40+
41+
# IntelliJ
42+
*.iml
43+
.idea/workspace.xml
44+
.idea/tasks.xml
45+
.idea/gradle.xml
46+
.idea/assetWizardSettings.xml
47+
.idea/dictionaries
48+
.idea/libraries
49+
# Android Studio 3 in .gitignore file.
50+
.idea/caches
51+
.idea/modules.xml
52+
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
53+
.idea/navEditor.xml
54+
55+
# Keystore files
56+
# Uncomment the following lines if you do not want to check your keystore files in.
57+
#*.jks
58+
#*.keystore
59+
60+
# External native build folder generated in Android Studio 2.2 and later
61+
.externalNativeBuild
62+
.cxx/
63+
64+
# Google Services (e.g. APIs or Firebase)
65+
# google-services.json
66+
67+
# Freeline
68+
freeline.py
69+
freeline/
70+
freeline_project_description.json
71+
72+
# fastlane
73+
fastlane/report.xml
74+
fastlane/Preview.html
75+
fastlane/screenshots
76+
fastlane/test_output
77+
fastlane/readme.md
78+
79+
# Version control
80+
vcs.xml
81+
82+
# lint
83+
lint/intermediates/
84+
lint/generated/
85+
lint/outputs/
86+
lint/tmp/
87+
# lint/reports/
88+
89+
# Android Profiling
90+
*.hprof
91+
92+
# Cordova plugins for Capacitor
93+
capacitor-cordova-android-plugins
94+
95+
# Copied web assets
96+
app/src/main/assets/public
97+
98+
# Generated Config files
99+
app/src/main/assets/capacitor.config.json
100+
app/src/main/assets/capacitor.plugins.json
101+
app/src/main/res/xml/config.xml
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/build/*
2+
!/build/.npmkeep
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
namespace "com.onesignal.example"
5+
compileSdk rootProject.ext.compileSdkVersion
6+
defaultConfig {
7+
applicationId "com.onesignal.example"
8+
minSdkVersion rootProject.ext.minSdkVersion
9+
targetSdkVersion rootProject.ext.targetSdkVersion
10+
versionCode 1
11+
versionName "1.0"
12+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13+
aaptOptions {
14+
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
15+
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
16+
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
17+
}
18+
}
19+
buildTypes {
20+
release {
21+
minifyEnabled false
22+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23+
}
24+
}
25+
}
26+
27+
repositories {
28+
flatDir{
29+
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
30+
}
31+
}
32+
33+
dependencies {
34+
implementation fileTree(include: ['*.jar'], dir: 'libs')
35+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
36+
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
37+
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
38+
implementation project(':capacitor-android')
39+
testImplementation "junit:junit:$junitVersion"
40+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
41+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
42+
implementation project(':capacitor-cordova-android-plugins')
43+
}
44+
45+
apply from: 'capacitor.build.gradle'
46+
47+
try {
48+
def servicesJSON = file('google-services.json')
49+
if (servicesJSON.text) {
50+
apply plugin: 'com.google.gms.google-services'
51+
}
52+
} catch(Exception e) {
53+
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
54+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile

0 commit comments

Comments
 (0)