@craft-native/android 0.0.436 → 0.0.443
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +44 -0
- package/dist/index.js +83 -4
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/templates/AndroidManifest.xml.template +2 -1
- package/templates/CraftHealthServices.kt.template +2 -0
- package/templates/CraftNativeCapabilities.kt.template +42 -1
- package/templates/CraftNativeMotion.kt.template +269 -0
- package/templates/CraftNativeServices.kt.template +6 -1
- package/templates/CraftPassiveSteps.kt.template +159 -0
- package/templates/CraftRecordingPressure.kt.template +156 -0
- package/templates/LocationRecordingService.kt.template +77 -9
- package/templates/MainActivity.kt.template +3 -0
- package/templates/MainActivityNative.kt.template +132 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type { AndroidMapProvider } from './native-map.js';
|
|
|
7
7
|
* well as the one-file bundle, and the app runs each screen from its own
|
|
8
8
|
* route's file. Stacks asks for route bundles only when this is true.
|
|
9
9
|
*/
|
|
10
|
+
/** Build-time proof for Stacks capability mappings, including unreleased source builds. */
|
|
11
|
+
export declare const nativeSensorCapabilities: readonly ['motionSensors', 'barometer', 'pedometer'];
|
|
10
12
|
export declare const nativeRouteBundles = true;
|
|
11
13
|
/**
|
|
12
14
|
* The app evaluates stx's shared runtime (`__runtime.js`, stx's
|
|
@@ -65,6 +67,12 @@ export interface CraftAndroidConfig {
|
|
|
65
67
|
enableSecureStorage?: boolean;
|
|
66
68
|
enableGeolocation?: boolean;
|
|
67
69
|
enableBackgroundLocation?: boolean;
|
|
70
|
+
/** Foreground raw Android sensors on native screens; separate from iOS fused motion. */
|
|
71
|
+
enableMotionSensors?: boolean;
|
|
72
|
+
/** Foreground pressure and session-relative altitude; does not enable background recording. */
|
|
73
|
+
enableBarometer?: boolean;
|
|
74
|
+
/** Foreground hardware step counters/detectors; requires activity recognition on Android 10+. */
|
|
75
|
+
enablePedometer?: boolean;
|
|
68
76
|
enableBluetooth?: boolean;
|
|
69
77
|
/**
|
|
70
78
|
* A Bluetooth heart-rate strap, or a watch broadcasting its heart rate (the
|
|
@@ -114,6 +122,18 @@ export interface CraftAndroidConfig {
|
|
|
114
122
|
}>;
|
|
115
123
|
trustedOrigins?: string[];
|
|
116
124
|
appIconPath?: string;
|
|
125
|
+
/**
|
|
126
|
+
* The launch splash: a directory laid out as Android resources, holding
|
|
127
|
+
* `drawable-<density>/splash_icon.png` (Android 12's splash icon, 288dp
|
|
128
|
+
* with its content inside the 192dp circle) and `splash_logo.png` (the
|
|
129
|
+
* logo the window background centres before Android 12), with Dark Mode
|
|
130
|
+
* ones in `drawable-night-<density>`. ts-images' `generateSplashScreens`
|
|
131
|
+
* writes exactly this (`android.resources`). Both sit on `backgroundColor`
|
|
132
|
+
* (`backgroundColorDark` at night), the colour the first frame continues.
|
|
133
|
+
* Without it, Android 12 shows the launcher icon and older versions the
|
|
134
|
+
* background colour.
|
|
135
|
+
*/
|
|
136
|
+
splashResources?: string;
|
|
117
137
|
/**
|
|
118
138
|
* The small icon in the status bar and on every notification the app
|
|
119
139
|
* shows, push or local: an Android vector drawable (`.xml`) or a `.png`,
|
|
@@ -260,6 +280,30 @@ export interface RunOptions {
|
|
|
260
280
|
device?: string;
|
|
261
281
|
output: string;
|
|
262
282
|
}
|
|
283
|
+
/** A splash file, by its place under `res/` (`drawable-night-xxhdpi/splash_icon.png`). */
|
|
284
|
+
export interface AndroidSplashFile {
|
|
285
|
+
folder: string;
|
|
286
|
+
name: 'splash_icon.png' | 'splash_logo.png';
|
|
287
|
+
path: string;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The splash files in a resources directory: `splash_icon.png` and
|
|
291
|
+
* `splash_logo.png` in each `drawable[-night][-<density>]` folder. A directory
|
|
292
|
+
* with neither is a mistake, not an app without a splash.
|
|
293
|
+
*/
|
|
294
|
+
export declare function androidSplashFiles(resources: string): AndroidSplashFile[];
|
|
295
|
+
/**
|
|
296
|
+
* The launch theme the activity starts in, and the theme it swaps to before
|
|
297
|
+
* its first frame. Android 12 and later draw their splash from
|
|
298
|
+
* `windowSplashScreen*`; earlier versions draw the window background, here
|
|
299
|
+
* the logo centred on the background colour. Either way the colour is the
|
|
300
|
+
* app's own `background`, so nothing flashes when the first frame replaces it.
|
|
301
|
+
*/
|
|
302
|
+
export declare function androidLaunchThemes(splash: Pick<AndroidSplashFile, 'name'>[]): {
|
|
303
|
+
base: string;
|
|
304
|
+
v31: string;
|
|
305
|
+
background?: string;
|
|
306
|
+
};
|
|
263
307
|
export declare function syncAndroidWebAssets(source: string, output: string): void;
|
|
264
308
|
export declare function renderAndroidPermissions(config: CraftAndroidConfig): string;
|
|
265
309
|
export declare function renderAndroidDeepLinks(config: CraftAndroidConfig): string;
|
package/dist/index.js
CHANGED
|
@@ -549,6 +549,7 @@ function compressNativeSources(target) {
|
|
|
549
549
|
if (packed.length < bytes.length)
|
|
550
550
|
writeFileSync(target, packed);
|
|
551
551
|
}
|
|
552
|
+
var nativeSensorCapabilities = ["motionSensors", "barometer", "pedometer"];
|
|
552
553
|
var nativeRouteBundles = true;
|
|
553
554
|
var nativeRouteRuntime = true;
|
|
554
555
|
var nativeMessages = true;
|
|
@@ -715,6 +716,9 @@ var DEFAULT_CONFIG = {
|
|
|
715
716
|
enableSecureStorage: false,
|
|
716
717
|
enableGeolocation: false,
|
|
717
718
|
enableBackgroundLocation: false,
|
|
719
|
+
enableMotionSensors: false,
|
|
720
|
+
enableBarometer: false,
|
|
721
|
+
enablePedometer: false,
|
|
718
722
|
enableBluetooth: false,
|
|
719
723
|
enableHeartRate: false,
|
|
720
724
|
enableHealthConnect: false,
|
|
@@ -753,6 +757,49 @@ function requireRegularFile(path, label) {
|
|
|
753
757
|
if (!statSync(path).isFile())
|
|
754
758
|
throw new Error(`${label} must be a file: ${path}`);
|
|
755
759
|
}
|
|
760
|
+
function androidSplashFiles(resources) {
|
|
761
|
+
if (!existsSync(resources) || !statSync(resources).isDirectory())
|
|
762
|
+
throw new Error(`Splash resources must be a directory: ${resources}`);
|
|
763
|
+
const files = [];
|
|
764
|
+
for (const folder of readdirSync(resources).sort()) {
|
|
765
|
+
if (!/^drawable(?:-night)?(?:-(?:l|m|tv|h|xh|xxh|xxxh)dpi)?$/.test(folder))
|
|
766
|
+
continue;
|
|
767
|
+
for (const name of ["splash_icon.png", "splash_logo.png"]) {
|
|
768
|
+
const path = join3(resources, folder, name);
|
|
769
|
+
if (existsSync(path) && statSync(path).isFile())
|
|
770
|
+
files.push({ folder, name, path });
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (!files.length)
|
|
774
|
+
throw new Error(`Splash resources hold no drawable*/splash_icon.png or splash_logo.png: ${resources}`);
|
|
775
|
+
return files;
|
|
776
|
+
}
|
|
777
|
+
function androidLaunchThemes(splash) {
|
|
778
|
+
const icon = splash.some((file) => file.name === "splash_icon.png");
|
|
779
|
+
const logo = splash.some((file) => file.name === "splash_logo.png");
|
|
780
|
+
const base = logo ? ` <style name="Theme.CraftApp.Launch" parent="Theme.CraftApp">
|
|
781
|
+
<item name="android:windowBackground">@drawable/craft_launch_background</item>
|
|
782
|
+
</style>
|
|
783
|
+
` : ` <style name="Theme.CraftApp.Launch" parent="Theme.CraftApp" />
|
|
784
|
+
`;
|
|
785
|
+
const v31 = `<?xml version="1.0" encoding="utf-8"?>
|
|
786
|
+
<resources>
|
|
787
|
+
<style name="Theme.CraftApp.Launch" parent="Theme.CraftApp">
|
|
788
|
+
<item name="android:windowSplashScreenBackground">@color/background</item>${icon ? `
|
|
789
|
+
<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>` : ""}
|
|
790
|
+
</style>
|
|
791
|
+
</resources>
|
|
792
|
+
`;
|
|
793
|
+
const background = logo ? `<?xml version="1.0" encoding="utf-8"?>
|
|
794
|
+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
|
|
795
|
+
<item android:drawable="@color/background" />
|
|
796
|
+
<item>
|
|
797
|
+
<bitmap android:gravity="center" android:src="@drawable/splash_logo" />
|
|
798
|
+
</item>
|
|
799
|
+
</layer-list>
|
|
800
|
+
` : undefined;
|
|
801
|
+
return { base, v31, background };
|
|
802
|
+
}
|
|
756
803
|
function containsPath(parent, candidate) {
|
|
757
804
|
const relativePath = relative(parent, candidate);
|
|
758
805
|
return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep}`) && !isAbsolute2(relativePath);
|
|
@@ -960,6 +1007,7 @@ function writeAndroidConfig(output, config) {
|
|
|
960
1007
|
writeFileSync(join3(output, "craft.config.json"), JSON.stringify(config, null, 2));
|
|
961
1008
|
const runtimeConfig = { ...config };
|
|
962
1009
|
delete runtimeConfig.appIconPath;
|
|
1010
|
+
delete runtimeConfig.splashResources;
|
|
963
1011
|
delete runtimeConfig.notificationIconPath;
|
|
964
1012
|
delete runtimeConfig.googleServicesFile;
|
|
965
1013
|
writeFileSync(join3(output, "app/src/main/assets/craft.config.json"), JSON.stringify(runtimeConfig, null, 2));
|
|
@@ -1013,10 +1061,14 @@ function renderAndroidPermissions(config) {
|
|
|
1013
1061
|
}
|
|
1014
1062
|
if (config.enablePushNotifications)
|
|
1015
1063
|
permissions.add("android.permission.POST_NOTIFICATIONS");
|
|
1016
|
-
if (config.enableKeepAwake)
|
|
1064
|
+
if (config.enableKeepAwake || config.enableBarometer && config.enableBackgroundLocation)
|
|
1017
1065
|
permissions.add("android.permission.WAKE_LOCK");
|
|
1018
1066
|
if (config.enableHealthConnect)
|
|
1019
1067
|
healthConnectPermissions(config).forEach((permission) => permissions.add(permission));
|
|
1068
|
+
if (config.enablePedometer)
|
|
1069
|
+
permissions.add("android.permission.ACTIVITY_RECOGNITION");
|
|
1070
|
+
if (config.enablePedometer && config.enableHealthServices)
|
|
1071
|
+
permissions.add("android.permission.RECEIVE_BOOT_COMPLETED");
|
|
1020
1072
|
if (config.renderer === "native" && config.backgroundRefresh?.enabled)
|
|
1021
1073
|
permissions.add("android.permission.RECEIVE_BOOT_COMPLETED");
|
|
1022
1074
|
if (config.enableHeartRate) {
|
|
@@ -1056,13 +1108,16 @@ function writeNativeShellSources(output, packagePath, packageName, config) {
|
|
|
1056
1108
|
write("CraftSnapshotFile.kt.template", "CraftSnapshotFile.kt");
|
|
1057
1109
|
write("CraftNativeImageCache.kt.template", "CraftNativeImageCache.kt");
|
|
1058
1110
|
write("CraftNativeHaptics.kt.template", "CraftNativeHaptics.kt");
|
|
1111
|
+
write("CraftNativeMotion.kt.template", "CraftNativeMotion.kt");
|
|
1059
1112
|
write("CraftNativeBackground.kt.template", "CraftNativeBackground.kt");
|
|
1060
1113
|
write(config.enableHealthConnect ? "CraftNativeHealth.kt.template" : "CraftNativeHealthStub.kt.template", "CraftNativeHealth.kt");
|
|
1061
1114
|
write(config.enableHealthServices ? "CraftHealthServices.kt.template" : "CraftHealthServicesStub.kt.template", "CraftHealthServices.kt");
|
|
1062
1115
|
if (config.enableHealthServices) {
|
|
1063
1116
|
write("CraftHealthServicesService.kt.template", "CraftHealthServicesService.kt");
|
|
1117
|
+
write("CraftPassiveSteps.kt.template", "CraftPassiveSteps.kt");
|
|
1064
1118
|
} else {
|
|
1065
1119
|
rmSync2(join3(javaDir, "CraftHealthServicesService.kt"), { force: true });
|
|
1120
|
+
rmSync2(join3(javaDir, "CraftPassiveSteps.kt"), { force: true });
|
|
1066
1121
|
}
|
|
1067
1122
|
write("CraftNativeServices.kt.template", "CraftNativeServices.kt", (source) => source.replace("{{NATIVE_PUSH_IMPORTS}}", config.enablePushNotifications ? "import com.google.firebase.messaging.FirebaseMessaging" : "").replace("{{NATIVE_WALLET_IMPORTS}}", config.enableWallet ? `import com.google.android.gms.pay.Pay
|
|
1068
1123
|
import com.google.android.gms.pay.PayApiAvailabilityStatus
|
|
@@ -1255,6 +1310,7 @@ async function init(options) {
|
|
|
1255
1310
|
if (config.appIconPath && ![".gif", ".jpg", ".png", ".webp"].includes(appIconExtension ?? "")) {
|
|
1256
1311
|
throw new Error(`Unsupported Android app icon format: ${appIconExtension || "(none)"}`);
|
|
1257
1312
|
}
|
|
1313
|
+
const splash = config.splashResources ? androidSplashFiles(config.splashResources) : [];
|
|
1258
1314
|
if (config.notificationIconPath)
|
|
1259
1315
|
requireRegularFile(config.notificationIconPath, "Notification icon");
|
|
1260
1316
|
const notificationIconExtension = config.notificationIconPath ? extname(config.notificationIconPath).toLowerCase() : undefined;
|
|
@@ -1348,6 +1404,7 @@ async function init(options) {
|
|
|
1348
1404
|
const nativeDir = join3(output, "app/src/main/java/com/craft/runtime");
|
|
1349
1405
|
mkdirSync2(nativeDir, { recursive: true });
|
|
1350
1406
|
writeFileSync(join3(nativeDir, "CraftNative.kt"), craftNative);
|
|
1407
|
+
writeFileSync(join3(nativeDir, "CraftRecordingPressure.kt"), readFileSync2(join3(TEMPLATES_DIR, "CraftRecordingPressure.kt.template"), "utf-8"));
|
|
1351
1408
|
const serviceTemplate = readFileSync2(join3(TEMPLATES_DIR, "LocationRecordingService.kt.template"), "utf-8");
|
|
1352
1409
|
writeFileSync(join3(nativeDir, "LocationRecordingService.kt"), serviceTemplate.replace(/\{\{PACKAGE_NAME\}\}/g, finalPackageName));
|
|
1353
1410
|
const healthTemplate = readFileSync2(join3(TEMPLATES_DIR, config.enableHealthConnect ? "CraftHealthConnect.kt.template" : "CraftHealthConnectStub.kt.template"), "utf-8");
|
|
@@ -1356,7 +1413,9 @@ async function init(options) {
|
|
|
1356
1413
|
writeFileSync(join3(output, "app/src/main/java", packagePath, file), readFileSync2(join3(TEMPLATES_DIR, template), "utf8").replace(/\{\{PACKAGE_NAME\}\}/g, finalPackageName));
|
|
1357
1414
|
}
|
|
1358
1415
|
const manifestTemplate = readFileSync2(join3(TEMPLATES_DIR, "AndroidManifest.xml.template"), "utf-8");
|
|
1359
|
-
const manifest = manifestTemplate.replace(/\{\{PACKAGE_NAME\}\}/g, finalPackageName).replace(/\{\{APP_NAME\}\}/g, name).replace(/\{\{PERMISSIONS\}\}/g, renderAndroidPermissions(config)).replace(/\{\{USES_CLEARTEXT\}\}/g, config.devServerURL?.startsWith("http://") || config.enableLocalNetwork ? "true" : "false").replace(/\{\{DEEP_LINK_INTENT_FILTERS\}\}/g, renderAndroidDeepLinks(config)).replace(/\{\{BACKGROUND_SERVICE\}\}/g, config.enableBackgroundLocation ? ' <service android:name="com.craft.runtime.LocationRecordingService" android:exported="false" android:foregroundServiceType="location" android:stopWithTask="false" />' : "").replace(/\{\{HEART_RATE_SERVICE\}\}/g, config.enableHeartRate ? ' <service android:name=".CraftHeartRateService" android:exported="false" android:foregroundServiceType="connectedDevice" />' : "").replace(/\{\{HEALTH_SERVICES_SERVICE\}\}/g, config.enableHealthServices ? ' <service android:name=".CraftHealthServicesService" android:exported="false" android:foregroundServiceType="health" android:stopWithTask="false" />'
|
|
1416
|
+
const manifest = manifestTemplate.replace(/\{\{PACKAGE_NAME\}\}/g, finalPackageName).replace(/\{\{APP_NAME\}\}/g, name).replace(/\{\{PERMISSIONS\}\}/g, renderAndroidPermissions(config)).replace(/\{\{USES_CLEARTEXT\}\}/g, config.devServerURL?.startsWith("http://") || config.enableLocalNetwork ? "true" : "false").replace(/\{\{DEEP_LINK_INTENT_FILTERS\}\}/g, renderAndroidDeepLinks(config)).replace(/\{\{BACKGROUND_SERVICE\}\}/g, config.enableBackgroundLocation ? ' <service android:name="com.craft.runtime.LocationRecordingService" android:exported="false" android:foregroundServiceType="location" android:stopWithTask="false" />' : "").replace(/\{\{HEART_RATE_SERVICE\}\}/g, config.enableHeartRate ? ' <service android:name=".CraftHeartRateService" android:exported="false" android:foregroundServiceType="connectedDevice" />' : "").replace(/\{\{HEALTH_SERVICES_SERVICE\}\}/g, config.enableHealthServices ? ' <service android:name=".CraftHealthServicesService" android:exported="false" android:foregroundServiceType="health" android:stopWithTask="false" />' + (config.enablePedometer ? `
|
|
1417
|
+
<service android:name=".CraftPassiveStepsService" android:exported="true" android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING" />
|
|
1418
|
+
<receiver android:name=".CraftPassiveStepsBootReceiver" android:exported="true"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver>` : "") : "").replace(/\{\{NATIVE_NOTIFICATION_RECEIVER\}\}/g, config.renderer === "native" ? renderNativeShellManifest(config) : "").replace(/\{\{CRASH_REPORTER_PROVIDER\}\}/g, ` <provider android:name=".CraftCrashReporterInit" android:authorities="\${applicationId}.craft-crash" android:exported="false" android:initOrder="1000" />`).replace(/\{\{GOOGLE_MAPS_API_KEY\}\}/g, config.mapProvider !== "maplibre" && config.mapsApiKey ? ` <meta-data android:name="com.google.android.geo.API_KEY" android:value="${escapeXml(config.mapsApiKey)}" />` : "").replace(/\{\{HEALTH_CONNECT_QUERIES\}\}/g, config.enableHealthConnect ? ` <queries>
|
|
1360
1419
|
<package android:name="com.google.android.apps.healthdata" />
|
|
1361
1420
|
</queries>` : "").replace(/\{\{HEALTH_CONNECT_RATIONALE\}\}/g, config.enableHealthConnect ? ` <intent-filter>
|
|
1362
1421
|
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
|
|
@@ -1461,6 +1520,17 @@ zipStorePath=wrapper/dists
|
|
|
1461
1520
|
</vector>
|
|
1462
1521
|
`);
|
|
1463
1522
|
}
|
|
1523
|
+
const resDir = join3(output, "app/src/main/res");
|
|
1524
|
+
for (const folder of existsSync(resDir) ? readdirSync(resDir) : []) {
|
|
1525
|
+
if (folder.startsWith("drawable"))
|
|
1526
|
+
for (const name of ["splash_icon.png", "splash_logo.png"])
|
|
1527
|
+
rmSync2(join3(resDir, folder, name), { force: true });
|
|
1528
|
+
}
|
|
1529
|
+
for (const file of splash) {
|
|
1530
|
+
mkdirSync2(join3(resDir, file.folder), { recursive: true });
|
|
1531
|
+
cpSync(file.path, join3(resDir, file.folder, file.name));
|
|
1532
|
+
}
|
|
1533
|
+
const launch = androidLaunchThemes(splash);
|
|
1464
1534
|
const themesXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
1465
1535
|
<resources>
|
|
1466
1536
|
<style name="Theme.CraftApp" parent="Theme.Material3.DayNight.NoActionBar">
|
|
@@ -1468,9 +1538,15 @@ zipStorePath=wrapper/dists
|
|
|
1468
1538
|
<item name="android:navigationBarColor">@color/primary</item>
|
|
1469
1539
|
<item name="android:windowBackground">@color/background</item>
|
|
1470
1540
|
</style>
|
|
1471
|
-
</resources>
|
|
1541
|
+
${launch.base}</resources>
|
|
1472
1542
|
`;
|
|
1473
1543
|
writeFileSync(join3(output, "app/src/main/res/values/themes.xml"), themesXml);
|
|
1544
|
+
mkdirSync2(join3(output, "app/src/main/res/values-v31"), { recursive: true });
|
|
1545
|
+
writeFileSync(join3(output, "app/src/main/res/values-v31/themes.xml"), launch.v31);
|
|
1546
|
+
if (launch.background)
|
|
1547
|
+
writeFileSync(join3(output, "app/src/main/res/drawable/craft_launch_background.xml"), launch.background);
|
|
1548
|
+
else
|
|
1549
|
+
rmSync2(join3(output, "app/src/main/res/drawable/craft_launch_background.xml"), { force: true });
|
|
1474
1550
|
const activityMainXml = config.renderer === "native" ? `<?xml version="1.0" encoding="utf-8"?>
|
|
1475
1551
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
1476
1552
|
android:id="@+id/native_root"
|
|
@@ -1694,6 +1770,8 @@ async function run(options) {
|
|
|
1694
1770
|
export {
|
|
1695
1771
|
ANDROID_MIN_SDK,
|
|
1696
1772
|
HEALTH_CONNECT_PERMISSIONS,
|
|
1773
|
+
androidLaunchThemes,
|
|
1774
|
+
androidSplashFiles,
|
|
1697
1775
|
build,
|
|
1698
1776
|
compressNativeSources,
|
|
1699
1777
|
createAndroidEmulator,
|
|
@@ -1704,6 +1782,7 @@ export {
|
|
|
1704
1782
|
nativeMessages,
|
|
1705
1783
|
nativeRouteBundles,
|
|
1706
1784
|
nativeRouteRuntime,
|
|
1785
|
+
nativeSensorCapabilities,
|
|
1707
1786
|
open,
|
|
1708
1787
|
renderAndroidDeepLinks,
|
|
1709
1788
|
renderAndroidPermissions,
|
|
@@ -1715,4 +1794,4 @@ export {
|
|
|
1715
1794
|
syncNativeFonts
|
|
1716
1795
|
};
|
|
1717
1796
|
|
|
1718
|
-
//# debugId=
|
|
1797
|
+
//# debugId=607F99B9A5B4A43764756E2164756E21
|