Users may see the domain of passwords stored with the Password AutoFill feature as airbridge.io or abr.ge.
After setting up deep links for the Airbridge SDK, if you utilize the Password AutoFill feature, the domain is saved as the applinks domain of the Airbridge deep link, which is airbridge.io or abr.ge.
The problem can be solved by setting up the webcredentials domain used in the Password AutoFill.
1. Prepare the domain that will store the password.
2. Host the JSON below at https://YOUR_DOMAIN/.well-known/apple-app-site-association with Content-Type: application/json. Your prepared domain should be entered instead of YOUR_DOMAIN.
You can find the App ID Prefix and Bundle ID in the [Identifiers]>[YOUR_APP] menu of the Apple Developer Portal.
{ "webcredentials": { "apps": ["YOUR_APP_ID_PREFIX.YOUR_BUNDLE_ID"] }}3. Navigate to [YOUR_PROJECT]>[Signing & Capabilities] in Xcode.
4. Click + Capability to add Associated Domains. Enter webcredentials:YOUR_DOMAIN in Associated Domains.
An error like below may occur when creating iOS builds with Cordova-Ionic SDK v2.0.1+.
ld: XCFrameworkIntermediates/AirBridge/AirBridge.framework/AirBridge(AirBridge-arm64-master.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE)Since Cordova-Ionic SDK v2.0.1+ uses Airbridge iOS SDK v1.28.0+, Bitcode is no longer supported. Please refer to the Bitcode compile error guide for more details.
Attention
This troubleshooting guide is for customers who need to migrate an existing AppDelegate-based app to UIScene(SceneDelegate) lifecycle.
When you run an app built with Xcode 27, the screen appears blank (white) or the app does not render properly.
Airbridge deep link events are not collected even when the app is opened through a scheme deep link or Universal Link.
The app does not work even though the code was added to AppDelegate as shown in the Initialize SDK and Collect deep link events in your app developer guide examples.
Apple is moving the app lifecycle from the UIApplicationDelegate-only AppDelegate model to the UIScene-based SceneDelegate model, and adopting the Scene lifecycle has effectively become required in the latest Xcode and iOS environments.
When an app adopts the Scene lifecycle through UIApplicationSceneManifest, the following AppDelegate callbacks are no longer called.
In cordova-ios 7.x and earlier, CDVAppDelegate creates the window and MainViewController in application:didFinishLaunchingWithOptions:. In the Scene lifecycle the window is owned by the SceneDelegate, so that window is never displayed and the screen stays blank.
The required work depends on your cordova-ios platform version. Check the version with cordova platform ls, then select the matching tab in each step below.
Attention
CDVSceneDelegate in cordova-ios 8.0.0 / 8.0.1 does not implement scene:continueUserActivity:, so applying the code below causes the app to terminate when it is opened through a Universal Link. Update to cordova-ios 8.1.0 or later before applying this guide.
This is already included in platforms/ios/App/App-Info.plist. Just confirm that no value is missing. UISceneStoryboardFile must be set to Main; without it the screen stays blank.
<key>UIApplicationSceneManifest</key><dict> <key>UIApplicationSupportsMultipleScenes</key> <false/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string> <key>UISceneStoryboardFile</key> <string>Main</string> </dict> </array> </dict></dict>Add the following UIApplicationSceneManifest to platforms/ios/YOUR_PROJECT_NAME/YOUR_PROJECT_NAME-Info.plist. cordova-ios 7.x and earlier have no Main.storyboard, so do not set UISceneStoryboardFile.
<key>UIApplicationSceneManifest</key><dict> <key>UIApplicationSupportsMultipleScenes</key> <false/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>SceneDelegate</string> </dict> </array> </dict></dict>This is already included in platforms/ios/App/App-Info.plist. Just confirm that no value is missing. UISceneStoryboardFile must be set to Main; without it the screen stays blank.
<key>UIApplicationSceneManifest</key><dict> <key>UIApplicationSupportsMultipleScenes</key> <false/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string> <key>UISceneStoryboardFile</key> <string>Main</string> </dict> </array> </dict></dict>Add the following UIApplicationSceneManifest to platforms/ios/YOUR_PROJECT_NAME/YOUR_PROJECT_NAME-Info.plist. cordova-ios 7.x and earlier have no Main.storyboard, so do not set UISceneStoryboardFile.
<key>UIApplicationSceneManifest</key><dict> <key>UIApplicationSupportsMultipleScenes</key> <false/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>SceneDelegate</string> </dict> </array> </dict></dict>The code below follows the default template language of each cordova-ios version: Swift for 8.1.0 or later, Objective-C for 7.x or earlier. If you implement it in the other language, also apply the following.
Implementing cordova-ios 8.1.0 or later in Objective-C: delete the provided App/SceneDelegate.swift and change UISceneDelegateClassName in App-Info.plist to SceneDelegate. #import "App-Swift.h" is required to call AirbridgeCordova, and do not import AppDelegate.h because it raises a build warning.
Modify platforms/ios/App/SceneDelegate.swift as follows.
import Cordova class SceneDelegate: CDVSceneDelegate { // when terminated app is opened with scheme deeplink or universal links override func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { // CDVSceneDelegate forwards connectionOptions.urlContexts to scene(_:openURLContexts:), // so scheme deeplinks are handled in scene(_:openURLContexts:) below. super.scene(scene, willConnectTo: session, options: connectionOptions) // CDVSceneDelegate does not forward connectionOptions.userActivities, // so delegate to scene(_:continue:) below. if let userActivity = connectionOptions.userActivities.first { self.scene(scene, continue: userActivity) } } // when backgrounded app is opened with scheme deeplink override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { // Must be called so that CDVPluginHandleOpenURLNotification reaches Cordova plugins. super.scene(scene, openURLContexts: URLContexts) // track deeplink if let context = URLContexts.first { AirbridgeCordova.trackDeeplink(url: context.url) } } // when backgrounded app is opened with universal links override func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { super.scene(scene, continue: userActivity) // track deeplink AirbridgeCordova.trackDeeplink(userActivity: userActivity) }}Implementing cordova-ios 7.x or earlier in Swift: change UISceneDelegateClassName to $(PRODUCT_MODULE_NAME).SceneDelegate, and add #import "AppDelegate.h", #import "MainViewController.h", and #import <Cordova/CDVPlugin.h> to platforms/ios/YOUR_PROJECT_NAME/Bridging-Header.h, which the platform provides by default. AirbridgeCordova is compiled into the app target, so no separate import is needed.
Add the following two files under platforms/ios/YOUR_PROJECT_NAME/Classes and include them in the app target in Xcode.
// SceneDelegate.h#import <UIKit/UIKit.h> API_AVAILABLE(ios(13.0))@interface SceneDelegate : UIResponder <UIWindowSceneDelegate> @property (strong, nonatomic) UIWindow *window; @end // SceneDelegate.m#import "SceneDelegate.h"#import "AppDelegate.h"#import "MainViewController.h"#import <Cordova/CDVPlugin.h>// The Airbridge Cordova-Ionic SDK is written in Swift.#import "YOUR_PROJECT_NAME-Swift.h" @implementation SceneDelegate // when terminated app is opened with scheme deeplink or universal links- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions{ if (![scene isKindOfClass:[UIWindowScene class]]) { return; } UIWindowScene *windowScene = (UIWindowScene *)scene; // In the Scene lifecycle, the window is owned by the SceneDelegate. // The window and MainViewController that CDVAppDelegate used to create must be // created here, otherwise the screen stays blank. MainViewController *viewController = [[MainViewController alloc] init]; self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; self.window.autoresizesSubviews = YES; self.window.rootViewController = viewController; [self.window makeKeyAndVisible]; // Populate AppDelegate's window/viewController properties for existing code that reads them. AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate; appDelegate.window = self.window; appDelegate.viewController = viewController; // track deeplink UIOpenURLContext *context = connectionOptions.URLContexts.allObjects.firstObject; if (context != nil) { [self postCordovaOpenURLNotificationWithContext:context]; [AirbridgeCordova trackDeeplinkWithUrl:context.URL]; } NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject; if (userActivity != nil) { [AirbridgeCordova trackDeeplinkWithUserActivity:userActivity]; }} // when backgrounded app is opened with scheme deeplink- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts{ UIOpenURLContext *context = URLContexts.allObjects.firstObject; if (context == nil) { return; } [self postCordovaOpenURLNotificationWithContext:context]; // track deeplink [AirbridgeCordova trackDeeplinkWithUrl:context.URL];} // when backgrounded app is opened with universal links- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity{ // track deeplink [AirbridgeCordova trackDeeplinkWithUserActivity:userActivity];} // Replaces the notification dispatch that CDVAppDelegate's application:openURL:options: performed.// Required for deep link handling in other Cordova plugins, such as window.handleOpenURL.- (void)postCordovaOpenURLNotificationWithContext:(UIOpenURLContext *)context API_AVAILABLE(ios(13.0)){ if (context.URL == nil) { return; } [[NSNotificationCenter defaultCenter] postNotificationName:CDVPluginHandleOpenURLNotification object:context.URL]; NSMutableDictionary *openURLData = [[NSMutableDictionary alloc] init]; [openURLData setValue:context.URL forKey:@"url"]; [openURLData setValue:context.options.sourceApplication forKey:@"sourceApplication"]; [openURLData setValue:context.options.annotation forKey:@"annotation"]; [[NSNotificationCenter defaultCenter] postNotificationName:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:openURLData];} @endAttention
On cordova-ios 8.1.0 or later, do not additionally call trackDeeplink(url:) with connectionOptions.urlContexts inside scene(_:willConnectTo:options:). CDVSceneDelegate forwards them to scene(_:openURLContexts:) again, so the deep link would be collected twice at cold start.
Implementing cordova-ios 8.1.0 or later in Objective-C: delete the provided App/SceneDelegate.swift and change UISceneDelegateClassName in App-Info.plist to SceneDelegate. #import "App-Swift.h" is required to call AirbridgeCordova, and do not import AppDelegate.h because it raises a build warning.
Modify platforms/ios/App/SceneDelegate.swift as follows.
import Cordova class SceneDelegate: CDVSceneDelegate { // when terminated app is opened with scheme deeplink or universal links override func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { // CDVSceneDelegate forwards connectionOptions.urlContexts to scene(_:openURLContexts:), // so scheme deeplinks are handled in scene(_:openURLContexts:) below. super.scene(scene, willConnectTo: session, options: connectionOptions) // CDVSceneDelegate does not forward connectionOptions.userActivities, // so delegate to scene(_:continue:) below. if let userActivity = connectionOptions.userActivities.first { self.scene(scene, continue: userActivity) } } // when backgrounded app is opened with scheme deeplink override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { // Must be called so that CDVPluginHandleOpenURLNotification reaches Cordova plugins. super.scene(scene, openURLContexts: URLContexts) // track deeplink if let context = URLContexts.first { AirbridgeCordova.trackDeeplink(url: context.url) } } // when backgrounded app is opened with universal links override func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { super.scene(scene, continue: userActivity) // track deeplink AirbridgeCordova.trackDeeplink(userActivity: userActivity) }}Implementing cordova-ios 7.x or earlier in Swift: change UISceneDelegateClassName to $(PRODUCT_MODULE_NAME).SceneDelegate, and add #import "AppDelegate.h", #import "MainViewController.h", and #import <Cordova/CDVPlugin.h> to platforms/ios/YOUR_PROJECT_NAME/Bridging-Header.h, which the platform provides by default. AirbridgeCordova is compiled into the app target, so no separate import is needed.
Add the following two files under platforms/ios/YOUR_PROJECT_NAME/Classes and include them in the app target in Xcode.
// SceneDelegate.h#import <UIKit/UIKit.h> API_AVAILABLE(ios(13.0))@interface SceneDelegate : UIResponder <UIWindowSceneDelegate> @property (strong, nonatomic) UIWindow *window; @end // SceneDelegate.m#import "SceneDelegate.h"#import "AppDelegate.h"#import "MainViewController.h"#import <Cordova/CDVPlugin.h>// The Airbridge Cordova-Ionic SDK is written in Swift.#import "YOUR_PROJECT_NAME-Swift.h" @implementation SceneDelegate // when terminated app is opened with scheme deeplink or universal links- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions{ if (![scene isKindOfClass:[UIWindowScene class]]) { return; } UIWindowScene *windowScene = (UIWindowScene *)scene; // In the Scene lifecycle, the window is owned by the SceneDelegate. // The window and MainViewController that CDVAppDelegate used to create must be // created here, otherwise the screen stays blank. MainViewController *viewController = [[MainViewController alloc] init]; self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; self.window.autoresizesSubviews = YES; self.window.rootViewController = viewController; [self.window makeKeyAndVisible]; // Populate AppDelegate's window/viewController properties for existing code that reads them. AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate; appDelegate.window = self.window; appDelegate.viewController = viewController; // track deeplink UIOpenURLContext *context = connectionOptions.URLContexts.allObjects.firstObject; if (context != nil) { [self postCordovaOpenURLNotificationWithContext:context]; [AirbridgeCordova trackDeeplinkWithUrl:context.URL]; } NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject; if (userActivity != nil) { [AirbridgeCordova trackDeeplinkWithUserActivity:userActivity]; }} // when backgrounded app is opened with scheme deeplink- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts{ UIOpenURLContext *context = URLContexts.allObjects.firstObject; if (context == nil) { return; } [self postCordovaOpenURLNotificationWithContext:context]; // track deeplink [AirbridgeCordova trackDeeplinkWithUrl:context.URL];} // when backgrounded app is opened with universal links- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity{ // track deeplink [AirbridgeCordova trackDeeplinkWithUserActivity:userActivity];} // Replaces the notification dispatch that CDVAppDelegate's application:openURL:options: performed.// Required for deep link handling in other Cordova plugins, such as window.handleOpenURL.- (void)postCordovaOpenURLNotificationWithContext:(UIOpenURLContext *)context API_AVAILABLE(ios(13.0)){ if (context.URL == nil) { return; } [[NSNotificationCenter defaultCenter] postNotificationName:CDVPluginHandleOpenURLNotification object:context.URL]; NSMutableDictionary *openURLData = [[NSMutableDictionary alloc] init]; [openURLData setValue:context.URL forKey:@"url"]; [openURLData setValue:context.options.sourceApplication forKey:@"sourceApplication"]; [openURLData setValue:context.options.annotation forKey:@"annotation"]; [[NSNotificationCenter defaultCenter] postNotificationName:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:openURLData];} @endAttention
On cordova-ios 8.1.0 or later, do not additionally call trackDeeplink(url:) with connectionOptions.urlContexts inside scene(_:willConnectTo:options:). CDVSceneDelegate forwards them to scene(_:openURLContexts:) again, so the deep link would be collected twice at cold start.
Leave the SDK initialization code (initializeSDK) in application:didFinishLaunchingWithOptions:
as is.
The application:openURL:options: and application:continueUserActivity:restorationHandler:
methods you wrote to collect deep links are not called in the Scene lifecycle, so after moving them to SceneDelegate, delete them from AppDelegate.
On cordova-ios 7.x or earlier, delete self.viewController = [[MainViewController alloc] init];
and return [super application:application didFinishLaunchingWithOptions:launchOptions];
, and return YES instead. The default CDVAppDelegate implementation creates a new window and CDVViewController, so leaving it in place creates a second Cordova web view that is never displayed.
A coroutine dependency error occurs during the build process with the following message.
java.lang.NoClassDefFoundError: kotlin/coroutines/AbstractCoroutineContextKey at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) ...If the kotlinx-coroutines-core library version is 1.3.5 or later, the kotlin-stdlib library version must be at a certain level or later.
Check whether the kotlin-stdlib library version is v.1.3.70 or later with the gradlew dependencies command. If the version is earlier than v.1.3.70, you need to update it.
Deeplink Open events that occur through the push notifications generated by the Braze SDK are not collected by Airbridge. Instead, the App Open event is collected.
The Airbridge SDK uses the dataString in the action and intent of the Activity to distinguish between Deeplink Open events and App Open events.
When a user opens the app through a push notification using the Braze SDK, the app goes through NotificationTrampolineActivity. This activity handles push notifications, but the dataString is not included in its action and intent, preventing the SDK from determining if it's a Deeplink Open event or an App Open event.
Add the following code to the android/app/src/main/java/.../MainApplication.kt file.
import co.ab180.airbridge.cordova.AirbridgeCordova import co.ab180.airbridge.cordova.common.AirbridgeLifecycleIntegration...AirbridgeCordova .setLifecycleIntegration = { activity -> return@setLifecycleIntegration activity .takeIf { it.javaClass.name == "com.braze.push.NotificationTrampolineActivity" } ?.run { intent?.extras?.getString("uri") }}import co.ab180.airbridge.cordova.AirbridgeCordova ;import co.ab180.airbridge.cordova.common.AirbridgeLifecycleIntegration;...AirbridgeCordova .setLifecycleIntegration(new AirbridgeLifecycleIntegration() { @Nullable @Override public String getDataString(@NonNull Activity activity) { if ( activity.getClass().getName().equals("com.braze.push.NotificationTrampolineActivity") && activity.getIntent() != null && activity.getIntent().getExtras() != null ) { return activity.getIntent().getExtras().getString("uri"); } return null; }});import co.ab180.airbridge.cordova.AirbridgeCordova import co.ab180.airbridge.cordova.common.AirbridgeLifecycleIntegration...AirbridgeCordova .setLifecycleIntegration = { activity -> return@setLifecycleIntegration activity .takeIf { it.javaClass.name == "com.braze.push.NotificationTrampolineActivity" } ?.run { intent?.extras?.getString("uri") }}import co.ab180.airbridge.cordova.AirbridgeCordova ;import co.ab180.airbridge.cordova.common.AirbridgeLifecycleIntegration;...AirbridgeCordova .setLifecycleIntegration(new AirbridgeLifecycleIntegration() { @Nullable @Override public String getDataString(@NonNull Activity activity) { if ( activity.getClass().getName().equals("com.braze.push.NotificationTrampolineActivity") && activity.getIntent() != null && activity.getIntent().getExtras() != null ) { return activity.getIntent().getExtras().getString("uri"); } return null; }});The "Manifest merger failed" error occurs during the build process.
The Airbridge SDK's AndroidManifest.xml includes rules to opt out of backing up the Shared Preferences data. The purpose of this rule is to avoid retaining the same Airbridge settings during the reinstallation of the app so that new installs or reinstalls can be detected accurately.
Merging Airbridge SDK backup rules with your app backup rules can cause conflicts.
Below are the opt-out rules defined in the Airbridge SDK.
<?xml version="1.0" encoding="utf-8"?><data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> </device-transfer></data-extraction-rules><?xml version="1.0" encoding="utf-8"?><full-backup-content> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /></full-backup-content><?xml version="1.0" encoding="utf-8"?><data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> </device-transfer></data-extraction-rules><?xml version="1.0" encoding="utf-8"?><full-backup-content> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /></full-backup-content>Adding android:fullBackupContent="string" to the AndroidManifest.xml file may cause an error like the following.
Manifest merger failed : Attribute application@fullBackupContent value=(string) from AndroidManifest.xmlTo fix this error,
add xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag
add tools:replace="android:fullBackupContent" to the <application> tag
in the AndroidManifest.xml file.
Adding android:dataExtractionRules="string resource" to the AndroidManifest.xml file may cause an error like the following.
Manifest merger failed : Attribute application@dataExtractionRules value=(string resource) from AndroidManifest.xml To fix this error,
add xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag
add tools:replace="android:dataExtractionRules" to the <application> tag
in the AndroidManifest.xml file.
Adding android:allowBackup="false" to the AndroidManifest.xml file may cause an error like the following.
Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:32:9-36 is also present at [:airbridge] AndroidManifest.xml:27:9-35 value=(true). Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:30:5-250:19 to override.To fix this error,
add xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag
add tools:replace="android:allowBackup" to the <application> tag
in the AndroidManifest.xml file.
The android:dataExtractionRules has been added in API Level 31. Therefore, if the compileSdkVersion is lower than 31, an error like the following may occur.
AndroidManifest.xml: AAPT: error: attribute android:dataExtractionRules not found.To fix this error,
add xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag
add tools:remove="android:dataExtractionRules" to the <application> tag
in the AndroidManifest.xml file.
For more guidance, refer to the articles below.
If an Airbridge SDK backup rule and a backup rule for a different third-party SDK (e.g., AppsFlyer SDK) overlap, you will see the build error below.
Attribute application@fullBackupContent value=(@xml/appsflyer_backup_rules) from [com.appsflyer:af-android-sdk:6.6.1] AndroidManifest.xml:14:18-73is also present at [io.airbridge:sdk-android:2.14.0] AndroidManifest.xml:27:18-78 value=(@xml/airbridge_auto_backup_rules).Suggestion: add 'tools:replace="android:fullBackupContent"' to <application> element at AndroidManifest.xml:7:5-13:19 to override.Overlapping of the Airbridge SDK backup rules and third-party SDK backup rules can cause build errors.
Create a android/app/src/main/res/xml folder.
Within the new xml folder, create a file (e.g. custom_backup_rules.xml).
Add the data backup rules defined in the Airbridge SDK as follows.
<?xml version="1.0" encoding="utf-8"?><full-backup-content> <!-- Airbridge Backup Rules --> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> <!-- Appsflyer Backup Rules --> <exclude domain="sharedpref" path="appsflyer-data"/> <!-- Your Custom Backup Rules --></full-backup-content>Within the created xml folder, create a file (e.g. custom_data_extraction_rules.xml).
Add the data backup rules defined in the Airbridge SDK as follows.
<?xml version="1.0" encoding="utf-8"?><data-extraction-rules> <cloud-backup> <!-- Airbridge Backup Rules --> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> <!-- Appsflyer Backup Rules --> <exclude domain="sharedpref" path="appsflyer-data"/> <!-- Your Custom Backup Rules --> </cloud-backup> <device-transfer> <!-- Airbridge Backup Rules --> <exclude domain="sharedpref" path="airbridge-internal" /> <exclude domain="sharedpref" path="airbridge-install" /> <exclude domain="sharedpref" path="airbridge-user-info" /> <exclude domain="sharedpref" path="airbridge-user-alias" /> <exclude domain="sharedpref" path="airbridge-user-attributes" /> <exclude domain="sharedpref" path="airbridge-device-alias" /> <exclude domain="database" path="airbridge.db" /> <!-- Appsflyer Backup Rules --> <exclude domain="sharedpref" path="appsflyer-data"/> <!-- Your Custom Backup Rules --> </device-transfer></data-extraction-rules><manifest ... xmlns:tools="http://schemas.android.com/tools"> <application ... android:allowBackup="true" android:fullBackupContent="@xml/custom_backup_rules" android:dataExtractionRules="@xml/custom_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules">GAID is being collected as 00000000-0000-0000-0000-000000000000 even though LAT (Limited Ad Tracking) is deactivated.
The AD_ID permission has been excluded due to other third-party libraries.
Add AD_ID permission.
<manifest ...> ... <uses-permission android:name="com.google.android.gms.permission.AD_ID" /> ...</manifest>When uploading your app to Google Play Console, you may receive the following warning or rejection messages:
"Your app doesn't support 16 KB page size"
"16 KB page size compatibility required"
App upload is rejected or displayed in a warning state
This is due to Google Play policy requirements that apps targeting Android 15 (API level 35) or higher must support 16KB page size.
To support 16 KB page sizes, the entire app (APK/AAB) must be packaged with 16 KB zipalign to pass Google Play policy.
If the APK/AAB is not built with 16 KB zipalign:
You will receive warning or rejection messages when uploading to Google Play Console
Uploads will be completely blocked after November 1, 2025
The app may not work properly on 16KB page size devices in the future
Known Issue in the Airbridge SDK: PT_GNU_RELRO Alignment
The Airbridge SDK has supported 16 KB page sizes since v4.6. However, in versions built with NDK r21, the LOAD segments of the native libraries (.so) are aligned to the 16 KB boundary, but the PT_GNU_RELRO segment is not.
App behavior is not affected. The app runs normally on 16 KB page size devices.
However, Google Play Console may display a 16 KB page size warning when you upload your app.
Alignment check tools such as Android Studio lint, APK Analyzer, and check_elf_alignment.sh may also report this as a warning.
This issue was resolved by upgrading the SDK build toolchain to NDK r27, and 16 KB page size support has been verified after the fix. Refer to the table below for the minimum version with 16 KB support and the recommended version for each platform.
Step 1: Check Airbridge SDK Version
Compare the Airbridge SDK version you are using against the table above.
If you are using a version lower than the Minimum Version with 16 KB Support:
16 KB page sizes are not supported. Be sure to update.
If you are using a version at or above the Minimum Version with 16 KB Support but below the Recommended Version:
The PT_GNU_RELRO alignment issue described above may cause Google Play Console to keep showing the warning. App behavior is not affected, but to resolve the warning, update to the Recommended Version or later.
Step 2: Check and Configure Android Gradle Plugin (AGP) Version
Check your project's current AGP version.
If using AGP 8.5.1 or higher:
16KB zipalign is automatically applied without any additional configuration.
Proceed directly to Step 3.
If using AGP 8.5.0 or lower:
Option A: Upgrade AGP to 8.5.1 or higher
Option B: Keep current AGP version + Add configuration
android { ... packagingOptions { jniLibs { useLegacyPackaging true } }}Step 3: Rebuild and Verify the App
After changing the configuration, perform a clean build of your app.
Step 4: Verify 16KB zipalign Application
Verify that the built APK/AAB is properly 16KB zipaligned.
Existing AppDelegate callback | Replacement callback in the Scene lifecycle ( |
|---|---|
|
|
Deep link at app cold start |
|
|
|
|
|
cordova-ios | cordova-ios | |
|---|---|---|
Deep link when the app is terminated | Scheme deep links are forwarded by | In |
스킴 딥링크(백그라운드) | In | Same |
유니버설 링크(백그라운드) | In | Same |
Platform | Minimum Version with 16 KB Support | Recommended Version (PT_GNU_RELRO issue fixed) |
|---|---|---|
Android | v4.6 | v4.9.4 |
React Native | v4.6 | v4.9.0 |
Cordova Ionic | v4.4.1 | x (support planned) |
Flutter | v4.6 | v4.9.0 |
Expo | v4.6 | v4.9.0 |
Unity | v4.6 | v4.9.2 |
Unreal | v4.6 | v4.9.0 |
Was this helpful?