From c7494698debfafa43a9d2bbff2c66ad99d2884d0 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Wed, 10 Jun 2026 10:52:02 -0700 Subject: [PATCH 1/2] feat: [SDK-4768] support disabling location module Co-authored-by: Cursor --- OneSignalCapacitorPlugin.podspec | 10 +++- Package.swift | 42 ++++++++++----- README.md | 54 +++++++++++++++++++ android/build.gradle.kts | 18 ++++++- .../capacitor/OneSignalCapacitorPlugin.kt | 26 +++++++-- 5 files changed, 132 insertions(+), 18 deletions(-) diff --git a/OneSignalCapacitorPlugin.podspec b/OneSignalCapacitorPlugin.podspec index c7b2ae9..451f330 100644 --- a/OneSignalCapacitorPlugin.podspec +++ b/OneSignalCapacitorPlugin.podspec @@ -1,6 +1,9 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) +onesignal_xcframework_version = '5.5.2' +onesignal_disable_location_env = ENV['ONESIGNAL_DISABLE_LOCATION'].to_s.strip.downcase +onesignal_disable_location = ['true', '1'].include?(onesignal_disable_location_env) Pod::Spec.new do |s| s.name = 'OnesignalCapacitorPlugin' @@ -20,5 +23,10 @@ Pod::Spec.new do |s| s.swift_version = '5.9' s.dependency 'Capacitor' - s.dependency 'OneSignalXCFramework', '5.5.2' + if onesignal_disable_location + s.dependency 'OneSignalXCFramework/OneSignal', onesignal_xcframework_version + s.dependency 'OneSignalXCFramework/OneSignalInAppMessages', onesignal_xcframework_version + else + s.dependency 'OneSignalXCFramework', onesignal_xcframework_version + end end diff --git a/Package.swift b/Package.swift index 3bd6043..891a551 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,34 @@ // swift-tools-version: 5.9 import PackageDescription +import Foundation + +func oneSignalEnvFlag(_ name: String) -> Bool { + let value = Context.environment[name]?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() + return value == "true" || value == "1" +} + +let oneSignalDisableLocation = oneSignalEnvFlag("ONESIGNAL_DISABLE_LOCATION") + +// InAppMessages, Location, and Extension are separate library products in +// OneSignal-XCFramework and must be linked explicitly under SPM. Location can +// be omitted for apps that do not use OneSignal.Location. +var oneSignalDependencies: [Target.Dependency] = [ + .product(name: "OneSignalFramework", package: "OneSignal-XCFramework"), + .product(name: "OneSignalInAppMessages", package: "OneSignal-XCFramework"), + .product(name: "OneSignalExtension", package: "OneSignal-XCFramework"), +] + +if !oneSignalDisableLocation { + oneSignalDependencies.append(.product(name: "OneSignalLocation", package: "OneSignal-XCFramework")) +} + +var capacitorPluginDependencies: [Target.Dependency] = [ + .product(name: "Capacitor", package: "capacitor-swift-pm"), + .product(name: "Cordova", package: "capacitor-swift-pm"), +] +capacitorPluginDependencies.append(contentsOf: oneSignalDependencies) +capacitorPluginDependencies.append("OSCapacitorLaunchOptions") let package = Package( name: "OnesignalCapacitorPlugin", @@ -28,19 +56,7 @@ let package = Package( ), .target( name: "OnesignalCapacitorPlugin", - dependencies: [ - .product(name: "Capacitor", package: "capacitor-swift-pm"), - .product(name: "Cordova", package: "capacitor-swift-pm"), - // InAppMessages and Location are separate library products in - // OneSignal-XCFramework and must be linked explicitly under SPM, - // otherwise their xcframeworks aren't loaded and the namespaces - // are silent no-ops at runtime. - .product(name: "OneSignalFramework", package: "OneSignal-XCFramework"), - .product(name: "OneSignalInAppMessages", package: "OneSignal-XCFramework"), - .product(name: "OneSignalLocation", package: "OneSignal-XCFramework"), - .product(name: "OneSignalExtension", package: "OneSignal-XCFramework"), - "OSCapacitorLaunchOptions" - ], + dependencies: capacitorPluginDependencies, path: "ios/Sources/OneSignalCapacitorPlugin" ) ] diff --git a/README.md b/README.md index 9a2a6a2..a37fdb9 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,60 @@ bunx cap sync npx cap sync ``` +## Disabling OneSignal Location + +If your app does not use `OneSignal.Location`, you can exclude the native OneSignal location module from iOS and Android builds. + +Set `ONESIGNAL_DISABLE_LOCATION=true` in the environment before resolving or building native dependencies. The value is case-insensitive, and `1` is also accepted. + +```bash +ONESIGNAL_DISABLE_LOCATION=true npx cap sync +``` + +In GitHub Actions, set it once at the job or step level so Swift Package Manager, CocoaPods, and Gradle builds inherit it: + +```yaml +env: + ONESIGNAL_DISABLE_LOCATION: true +``` + +With the location module disabled, calls to `OneSignal.Location` are ignored on Android and `OneSignal.Location.isShared()` resolves `false`. + +### Applying the change + +The environment variable is read when native dependencies are resolved. If you change the variable in an existing project, clear the relevant cache and re-resolve in a shell where the variable is exported. + +> [!IMPORTANT] +> When using Xcode or Android Studio, launch the IDE from a terminal that has `ONESIGNAL_DISABLE_LOCATION` exported. An IDE launched from the Dock/Finder does not inherit variables set only in your shell profile. + +Swift Package Manager: + +```bash +rm -rf ~/Library/Caches/org.swift.swiftpm ~/Library/Developer/Xcode/DerivedData/* +ONESIGNAL_DISABLE_LOCATION=true npx cap sync ios +``` + +In Xcode, you can instead use **File -> Packages -> Reset Package Caches** with the variable exported, then build. + +CocoaPods: + +```bash +cd ios/App +pod deintegrate +rm -rf Pods Podfile.lock +ONESIGNAL_DISABLE_LOCATION=true pod install +``` + +Android Gradle, which re-reads the variable on each configuration: + +```bash +ONESIGNAL_DISABLE_LOCATION=true npx cap sync android +cd android +ONESIGNAL_DISABLE_LOCATION=true ./gradlew assembleDebug +``` + +On CI, key any DerivedData, SwiftPM, CocoaPods, or Gradle caches on the value of `ONESIGNAL_DISABLE_LOCATION` so a restored cache does not resurrect the location module. + ## Usage ```ts diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 0c8f07b..dcb4477 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -84,8 +84,18 @@ fun propertyOrCatalog(propertyName: String, catalogKey: String): String = fun intPropertyOrCatalog(propertyName: String, catalogKey: String): Int = project.findProperty(propertyName)?.toString()?.toInt() ?: catalogVersion(catalogKey).toInt() +fun flagOrProperty(envName: String, propertyName: String): Boolean { + val value = System.getenv(envName) + ?: project.findProperty(propertyName)?.toString() + ?: rootProject.findProperty(propertyName)?.toString() + val normalizedValue = value?.trim() + return normalizedValue.equals("true", ignoreCase = true) || normalizedValue == "1" +} + val junitVersion: String = propertyOrCatalog("junitVersion", "junit") val androidxAppCompatVersion: String = propertyOrCatalog("androidxAppCompatVersion", "androidxAppCompat") +val oneSignalVersion: String = catalogVersion("onesignal") +val oneSignalDisableLocation: Boolean = flagOrProperty("ONESIGNAL_DISABLE_LOCATION", "onesignal.disableLocation") extra["junitVersion"] = junitVersion extra["androidxAppCompatVersion"] = androidxAppCompatVersion @@ -126,7 +136,13 @@ repositories { dependencies { "implementation"(project(":capacitor-android")) "implementation"("androidx.appcompat:appcompat:$androidxAppCompatVersion") - "implementation"("com.onesignal:OneSignal:${catalogVersion("onesignal")}") + if (oneSignalDisableLocation) { + "implementation"("com.onesignal:core:$oneSignalVersion") + "implementation"("com.onesignal:notifications:$oneSignalVersion") + "implementation"("com.onesignal:in-app-messages:$oneSignalVersion") + } else { + "implementation"("com.onesignal:OneSignal:$oneSignalVersion") + } "testImplementation"("junit:junit:$junitVersion") "androidTestImplementation"("androidx.test.ext:junit:${catalogVersion("androidxTestJunit")}") "androidTestImplementation"("androidx.test.espresso:espresso-core:${catalogVersion("androidxEspresso")}") diff --git a/android/src/main/kotlin/com/onesignal/capacitor/OneSignalCapacitorPlugin.kt b/android/src/main/kotlin/com/onesignal/capacitor/OneSignalCapacitorPlugin.kt index c0a0be0..2c102e4 100644 --- a/android/src/main/kotlin/com/onesignal/capacitor/OneSignalCapacitorPlugin.kt +++ b/android/src/main/kotlin/com/onesignal/capacitor/OneSignalCapacitorPlugin.kt @@ -7,6 +7,7 @@ import com.getcapacitor.PluginMethod import com.getcapacitor.annotation.CapacitorPlugin import com.onesignal.OneSignal import com.onesignal.common.OneSignalWrapper +import com.onesignal.debug.internal.logging.Logging import com.onesignal.inAppMessages.IInAppMessageClickEvent import com.onesignal.inAppMessages.IInAppMessageClickListener import com.onesignal.inAppMessages.IInAppMessageDidDismissEvent @@ -44,6 +45,8 @@ class OneSignalCapacitorPlugin : Plugin(), // provisional (3), and ephemeral (4) states do not apply here. private const val PERMISSION_DENIED = 1 private const val PERMISSION_AUTHORIZED = 2 + private const val LOCATION_MODULE_NOT_AVAILABLE = + "OneSignal location module is not available. Add the location dependency to use OneSignal.Location." } private val notificationWillDisplayCache = mutableMapOf() @@ -56,6 +59,10 @@ class OneSignalCapacitorPlugin : Plugin(), // call into the dead Capacitor bridge. private val pluginScope = MainScope() + private fun logLocationModuleNotAvailable(throwable: Throwable) { + Logging.error(LOCATION_MODULE_NOT_AVAILABLE, throwable) + } + private val permissionObserver = object : IPermissionObserver { override fun onNotificationPermissionChange(permission: Boolean) { val ret = JSObject() @@ -640,7 +647,11 @@ class OneSignalCapacitorPlugin : Plugin(), @PluginMethod fun requestLocationPermission(call: PluginCall) { pluginScope.launch { - OneSignal.Location.requestPermission() + try { + OneSignal.Location.requestPermission() + } catch (t: Throwable) { + logLocationModuleNotAvailable(t) + } call.resolve() } } @@ -648,14 +659,23 @@ class OneSignalCapacitorPlugin : Plugin(), @PluginMethod fun setLocationShared(call: PluginCall) { val shared = call.getBoolean("shared") ?: false - OneSignal.Location.isShared = shared + try { + OneSignal.Location.isShared = shared + } catch (t: Throwable) { + logLocationModuleNotAvailable(t) + } call.resolve() } @PluginMethod fun isLocationShared(call: PluginCall) { val ret = JSObject() - ret.put("shared", OneSignal.Location.isShared) + try { + ret.put("shared", OneSignal.Location.isShared) + } catch (t: Throwable) { + logLocationModuleNotAvailable(t) + ret.put("shared", false) + } call.resolve(ret) } From 534149558e31c34eaff22454c8df2bba563606ae Mon Sep 17 00:00:00 2001 From: Fadi George Date: Wed, 10 Jun 2026 16:42:41 -0700 Subject: [PATCH 2/2] refactor: [SDK-4768] env-only flag for disabling location --- android/build.gradle.kts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index dcb4477..c27d0fc 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -84,10 +84,8 @@ fun propertyOrCatalog(propertyName: String, catalogKey: String): String = fun intPropertyOrCatalog(propertyName: String, catalogKey: String): Int = project.findProperty(propertyName)?.toString()?.toInt() ?: catalogVersion(catalogKey).toInt() -fun flagOrProperty(envName: String, propertyName: String): Boolean { +fun envFlag(envName: String): Boolean { val value = System.getenv(envName) - ?: project.findProperty(propertyName)?.toString() - ?: rootProject.findProperty(propertyName)?.toString() val normalizedValue = value?.trim() return normalizedValue.equals("true", ignoreCase = true) || normalizedValue == "1" } @@ -95,7 +93,7 @@ fun flagOrProperty(envName: String, propertyName: String): Boolean { val junitVersion: String = propertyOrCatalog("junitVersion", "junit") val androidxAppCompatVersion: String = propertyOrCatalog("androidxAppCompatVersion", "androidxAppCompat") val oneSignalVersion: String = catalogVersion("onesignal") -val oneSignalDisableLocation: Boolean = flagOrProperty("ONESIGNAL_DISABLE_LOCATION", "onesignal.disableLocation") +val oneSignalDisableLocation: Boolean = envFlag("ONESIGNAL_DISABLE_LOCATION") extra["junitVersion"] = junitVersion extra["androidxAppCompatVersion"] = androidxAppCompatVersion