Platform Setup
alphyn-cli integrate performs everything on this page. It is documented here so you can see
what the integration consists of, verify it, or reproduce it in an unusual project layout.
Run alphyn-cli doctor to check any project against it.
Android
Section titled “Android”Requirements
Section titled “Requirements”minSdkVersion26or higher.targetSdkVersion35recommended.
Permissions: nothing to add
Section titled “Permissions: nothing to add”The SDK declares its own permissions and they merge into your app automatically. You do not
need to copy them into android/app/src/main/AndroidManifest.xml. For reference, the merged
set is:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="com.android.keystore.CERTIFICATE_ACCESS" /><uses-permission android:name="android.permission.USE_CREDENTIALS" /><uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS" />Gradle wiring: required
Section titled “Gradle wiring: required”Two changes to your Android project are required. integrate writes both, bounded by
alphyn: markers.
1. The SDK’s Maven repository, in the Android root build script.
The Android native (com.byterialab:alphyn-sdk) is served from the Alphyn package registry.
React Native resolves dependencies from project-level repositories, so :app cannot see the SDK
module’s own repository and the build fails without this authenticated registry block in
android/build.gradle:
allprojects { repositories { maven { url System.getenv('ALPHYN_REGISTRY_URL') ?: 'https://packages.byterialab.com/maven' credentials { username = 'x' password = System.getenv('ALPHYN_REGISTRY_KEY') ?: '' } } }}The build reads your app API key from ALPHYN_REGISTRY_KEY; see
SDK Registry Access. Omit the repository, or build without the key,
and the Android build fails at dependency resolution:
FAILURE: Build failed with an exception.> Could not resolve all dependencies for configuration ':app:debugCompileClasspath'. > Could not find com.byterialab:alphyn-sdk:<version>. Required by: project ':app' > project :alphyn_react-native-sdk2. The build registration hook, in android/app/build.gradle.
Every Android build has to register its app hash - the SHA-256 of the signing certificate -
with the backend, otherwise the app fails attestation at runtime. integrate installs a Gradle hook that does this on every build, using
the API key it provisions into a gitignored .alphyn/android-api.key. The hook is generated
code and is not meant to be pasted by hand; install it with alphyn-cli integrate.
Without the hook, register each build explicitly instead:
alphyn-cli register --apk android/app/build/outputs/apk/release/app-release.apkUnregistered builds fail attestation at runtime with no build-time error, so alphyn-cli doctor is the check worth running before you ship.
ProGuard / R8: nothing to add
Section titled “ProGuard / R8: nothing to add”The SDK ships consumer-rules.pro inside the AAR and R8 applies it to your app
automatically. You do not need keep rules of your own for the SDK.
When the SDK starts on Android
Section titled “When the SDK starts on Android”In a bare React Native project the SDK starts when your JavaScript reaches
AlphynSDK.initialize(). If that call sits inside a useEffect, everything before the first
render runs unprotected.
Managed Expo projects also get a launch-time initializer: the config plugin adds a
com.alphyn.sdk.AUTO_INIT manifest entry, and the SDK starts through App Startup before the
JavaScript bundle loads. It is opt-in and only that plugin writes it, so a bare project is
unaffected. To start earlier in a bare project, call initialize() from your entry point
rather than from a component.
Requirements
Section titled “Requirements”- iOS
15.0or later. Set it inios/Podfile:
platform :ios, '15.0'Info.plist
Section titled “Info.plist”integrate merges these keys. The scheme list is what the jailbreak detector probes; a
shortened list silently reduces detection coverage.
<key>BGTaskSchedulerPermittedIdentifiers</key><array> <string>com.byterialab.backgroundcheck</string></array>
<key>UIBackgroundModes</key><array> <string>fetch</string></array>
<key>LSApplicationQueriesSchemes</key><array> <string>cydia</string> <string>sileo</string> <string>zbra</string> <string>filza</string> <string>undecimus</string> <string>installer</string> <string>taig</string> <string>dopamine</string> <string>trollstore</string> <string>trollstorehelper</string></array>
<key>NSAppTransportSecurity</key><dict> <key>NSAllowsArbitraryLoads</key> <false/> <key>NSAllowsLocalNetworking</key> <true/> <key>NSExceptionDomains</key> <dict> <key>alphyn-attestation-api.byterialab.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> </dict></dict>The SDK does not use location services and needs no location usage description.
AppDelegate
Section titled “AppDelegate”The SDK starts at launch, before React Native loads its JavaScript bundle, through a single
launch-time entry point. integrate installs this call into your Swift AppDelegate, bounded by
alphyn:init markers, and adds import react_native_alphyn_sdk (bounded by its own markers):
import UIKitimport react_native_alphyn_sdk
@mainclass AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { AlphynReactNativeLauncher.launch(interval: 45, debugHash: nil)
// Continue with your React Native setup here. return true }}AlphynReactNativeLauncher.launch runs AlphynSDK.register() synchronously (it claims the
background-task identifiers and must run at launch; it cannot be deferred to JavaScript) and then
starts the SDK. register() cannot fail the launch, and initialization runs asynchronously.
When an iOS debug hash is pinned, integrate renders the launch call under #if DEBUG with the
hash as the debugHash: argument, and the release branch with debugHash: nil, so a release build
never carries it.
Initializing at launch and from JavaScript is not a conflict. The launcher and the JavaScript
initialize() go through one shared gate: whichever runs first starts the SDK once, and the other
becomes a safe no-op, so a second scanner never starts. On iOS the launcher wins (it runs before
the bundle loads); the JavaScript call is what starts the SDK on bare React Native Android.
Archive registration
Section titled “Archive registration”integrate installs a post-action into the app’s shared Xcode scheme, so archive builds
register themselves. Debug and simulator builds never register, which is why the development
loop needs a pinned --ios-debug-hash.
A terminal or CI archive runs the same post-action:
cd iosxcodebuild -workspace <App>.xcworkspace -scheme <AppScheme> -configuration Release \ -destination 'generic/platform=iOS' archive -archivePath build/App.xcarchiveObjective-C AppDelegate (React Native ≤ 0.76 templates)
Section titled “Objective-C AppDelegate (React Native ≤ 0.76 templates)”The managed hook requires a Swift AppDelegate; alphyn-cli doctor reports it rather than
installing a hook that would not run. If your app still uses AppDelegate.mm, expose the call
through a small Swift shim. Add AlphynBootstrap.swift to your iOS target and accept Xcode’s
offer to create a bridging header:
import Alphynimport Foundation
@objc(AlphynBootstrap)public final class AlphynBootstrap: NSObject { @objc(registerSDKAndReturnError:) public static func registerSDK(_ errorPointer: NSErrorPointer) -> Bool { do { try AlphynSDK.register() return true } catch { errorPointer?.pointee = error as NSError return false } }}Then call it from AppDelegate.mm before React Native starts:
#if __has_include("YourAppName-Swift.h")#import "YourAppName-Swift.h"#else#import <YourAppName/YourAppName-Swift.h>#endif
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSError *error = nil; [AlphynBootstrap registerSDKAndReturnError:&error]; if (error) { NSLog(@"Failed to register AlphynSDK background tasks: %@", error.localizedDescription); }
// ... your existing React Native setup ... return [super application:application didFinishLaunchingWithOptions:launchOptions];}With an Objective-C AppDelegate the SDK is initialized from JavaScript only; register()
still has to happen natively, as above.
Important notes:
AlphynSDK.register()cannot be deferred to JavaScript.- Call
register()before creating the React Native bridge. - If you change
Info.plistbackground-task settings, uninstall and reinstall the app on the device or simulator.