Skip to content

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.

  • minSdkVersion 26 or higher.
  • targetSdkVersion 35 recommended.

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" />

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-sdk

2. 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:

Terminal window
alphyn-cli register --apk android/app/build/outputs/apk/release/app-release.apk

Unregistered builds fail attestation at runtime with no build-time error, so alphyn-cli doctor is the check worth running before you ship.

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.

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.

  • iOS 15.0 or later. Set it in ios/Podfile:
platform :ios, '15.0'

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.

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 UIKit
import react_native_alphyn_sdk
@main
class 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.

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:

Terminal window
cd ios
xcodebuild -workspace <App>.xcworkspace -scheme <AppScheme> -configuration Release \
-destination 'generic/platform=iOS' archive -archivePath build/App.xcarchive

Objective-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 Alphyn
import 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.plist background-task settings, uninstall and reinstall the app on the device or simulator.