Skip to content

Commit 7ada697

Browse files
huhuanmingclaude
andauthored
feat: add buildNumber change detection and getBuiltinBundleVersion API (#38)
* feat: add buildNumber change detection, getBuiltinBundleVersion API, and bump to 1.1.40 - Detect native buildNumber changes and clear hot-update bundle data to fall back to builtin bundle - Add getNativeBuildNumber() and getBuiltinBundleVersion() TS interfaces with iOS/Android implementations - Clear both nativeVersion and nativeBuildNumber prefs on version or buildNumber change - Extract clearNativeVersionPrefs helper to avoid hardcoded strings - Add BUNDLE_VERSION env var injection in example app (Android meta-data + iOS Info.plist) - Add example buttons for new APIs in BundleUpdateTestPage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 1.1.40 * fix(ios): guard against empty stored buildNumber to match Android behavior * chore: bump all @onekeyfe native packages to 1.1.41 * fix(android): use get().toString() for numeric meta-data in getBuiltinBundleVersion * docs: update CHANGELOG for 1.1.41 --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2c0348a commit 7ada697

26 files changed

Lines changed: 189 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.1.41] - 2026-03-17
6+
7+
### Features
8+
- **bundle-update**: Add buildNumber change detection in `getJsBundlePath()` — clears hot-update bundle data and falls back to builtin JS bundle when native buildNumber changes
9+
- **bundle-update**: Add `getNativeBuildNumber()` and `getBuiltinBundleVersion()` APIs on both iOS and Android
10+
11+
### Bug Fixes
12+
- **bundle-update (iOS)**: Guard against empty stored buildNumber to match Android behavior in build number change detection
13+
- **bundle-update (Android)**: Use `get().toString()` instead of `getString()` in `getBuiltinBundleVersion()` to handle numeric meta-data values that AAPT2 stores as Integer
14+
15+
### Chores
16+
- Bump all native modules and views to 1.1.41
17+
518
## [1.1.39] - 2026-03-17
619

720
### Features

example/react-native/android/app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ android {
8888
targetSdkVersion rootProject.ext.targetSdkVersion
8989
versionCode 1
9090
versionName "1.0"
91+
manifestPlaceholders += [BUNDLE_VERSION: System.getenv('BUNDLE_VERSION') ?: '1']
9192
}
9293
signingConfigs {
9394
debug {

example/react-native/android/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
android:theme="@style/AppTheme"
1212
android:usesCleartextTraffic="${usesCleartextTraffic}"
1313
android:supportsRtl="true">
14+
<meta-data
15+
android:name="BUNDLE_VERSION"
16+
android:value="${BUNDLE_VERSION}" />
1417
<activity
1518
android:name=".MainActivity"
1619
android:label="@string/app_name"

example/react-native/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,7 +2839,7 @@ PODS:
28392839
- ReactNativeNativeLogger
28402840
- SocketRocket
28412841
- Yoga
2842-
- ReactNativeBundleUpdate (1.1.39):
2842+
- ReactNativeBundleUpdate (1.1.40):
28432843
- boost
28442844
- DoubleConversion
28452845
- fast_float
@@ -3609,7 +3609,7 @@ SPEC CHECKSUMS:
36093609
ReactCodegen: 554b421c45b7df35ac791da1b734335470b55fcc
36103610
ReactCommon: 424cc34cf5055d69a3dcf02f3436481afb8b0f6f
36113611
ReactNativeAppUpdate: 07053378aecfdaaa23877f75c9c067fef7d58415
3612-
ReactNativeBundleUpdate: 752f40fd03fa3a6701318ab83de69f420d550053
3612+
ReactNativeBundleUpdate: 6b4bccc4975bd20ad6b2dfbca1f21da62d2b2e8d
36133613
ReactNativeCheckBiometricAuthChanged: 3fbd6bdc758ccc059ad2feaf3214b871c0ccf31e
36143614
ReactNativeDeviceUtils: cb1fa6e62e1ab4743fd9654f0124b23637ba62c5
36153615
ReactNativeGetRandomValues: 7b24b5b17f6a676724bb673d76a8f9b0871aa4c7

example/react-native/ios/example/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
<string>????</string>
2525
<key>CFBundleVersion</key>
2626
<string>$(CURRENT_PROJECT_VERSION)</string>
27+
<key>BUNDLE_VERSION</key>
28+
<string>$(BUNDLE_VERSION)</string>
2729
<key>LSRequiresIPhoneOS</key>
2830
<true/>
2931
<key>NSAppTransportSecurity</key>

example/react-native/pages/BundleUpdateTestPage.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,22 @@ H3bEFZ8=
497497
setUtilError(err instanceof Error ? err.message : 'Unknown error');
498498
}
499499
};
500+
const utilGetNativeBuildNumber = async () => {
501+
clearUtil();
502+
try {
503+
setUtilResult({ nativeBuildNumber: await ReactNativeBundleUpdate.getNativeBuildNumber() });
504+
} catch (err) {
505+
setUtilError(err instanceof Error ? err.message : 'Unknown error');
506+
}
507+
};
508+
const utilGetBuiltinBundleVersion = async () => {
509+
clearUtil();
510+
try {
511+
setUtilResult({ builtinBundleVersion: await ReactNativeBundleUpdate.getBuiltinBundleVersion() });
512+
} catch (err) {
513+
setUtilError(err instanceof Error ? err.message : 'Unknown error');
514+
}
515+
};
500516
const utilGetFallbackData = async () => {
501517
clearUtil();
502518
try {
@@ -691,6 +707,8 @@ H3bEFZ8=
691707
<TestButton title="Get Web Embed Path" onPress={utilGetWebEmbedPath} />
692708
<TestButton title="Get JS Bundle Path" onPress={utilGetJsBundlePath} />
693709
<TestButton title="Get Native App Version" onPress={utilGetNativeAppVersion} />
710+
<TestButton title="Get Native Build Number" onPress={utilGetNativeBuildNumber} />
711+
<TestButton title="Get Builtin Bundle Version" onPress={utilGetBuiltinBundleVersion} />
694712
<TestButton title="Get Fallback Bundle Data" onPress={utilGetFallbackData} />
695713
<TestButton title="List Local Bundles" onPress={utilListLocal} />
696714
<TestButton title="List ASC Files" onPress={utilListAscFiles} />

native-modules/native-logger/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onekeyfe/react-native-native-logger",
3-
"version": "1.1.39",
3+
"version": "1.1.41",
44
"description": "react-native-native-logger",
55
"main": "./lib/module/index.js",
66
"types": "./lib/typescript/src/index.d.ts",

native-modules/react-native-app-update/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onekeyfe/react-native-app-update",
3-
"version": "1.1.39",
3+
"version": "1.1.41",
44
"description": "react-native-app-update",
55
"main": "./lib/module/index.js",
66
"types": "./lib/typescript/src/index.d.ts",

native-modules/react-native-background-thread/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onekeyfe/react-native-background-thread",
3-
"version": "1.1.39",
3+
"version": "1.1.41",
44
"description": "react-native-background-thread",
55
"main": "./lib/module/index.js",
66
"types": "./lib/typescript/src/index.d.ts",

native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ P2Q5dClenjjjVA==
9595
object BundleUpdateStoreAndroid {
9696
private val bcProvider = BouncyCastleProvider()
9797
private const val PREFS_NAME = "BundleUpdatePrefs"
98-
private const val NATIVE_VERSION_PREFS_NAME = "NativeVersionPrefs"
98+
internal const val NATIVE_VERSION_PREFS_NAME = "NativeVersionPrefs"
9999
private const val CURRENT_BUNDLE_VERSION_KEY = "currentBundleVersion"
100100

101101
fun getDownloadBundleDir(context: Context): String {
@@ -207,6 +207,47 @@ object BundleUpdateStoreAndroid {
207207
prefs.edit().putString("nativeVersion", nativeVersion).apply()
208208
}
209209

210+
fun getBuildNumber(context: Context): String {
211+
return try {
212+
val pm = context.packageManager
213+
val pi = pm.getPackageInfo(context.packageName, 0)
214+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
215+
pi.longVersionCode.toString()
216+
} else {
217+
@Suppress("DEPRECATION")
218+
pi.versionCode.toString()
219+
}
220+
} catch (e: Exception) {
221+
OneKeyLog.error("BundleUpdate", "Error getting build number: ${e.message}")
222+
""
223+
}
224+
}
225+
226+
fun getNativeBuildNumber(context: Context): String {
227+
val prefs = context.getSharedPreferences(NATIVE_VERSION_PREFS_NAME, Context.MODE_PRIVATE)
228+
return prefs.getString("nativeBuildNumber", "") ?: ""
229+
}
230+
231+
fun setNativeBuildNumber(context: Context, buildNumber: String) {
232+
val prefs = context.getSharedPreferences(NATIVE_VERSION_PREFS_NAME, Context.MODE_PRIVATE)
233+
prefs.edit().putString("nativeBuildNumber", buildNumber).apply()
234+
}
235+
236+
fun clearNativeVersionPrefs(context: Context) {
237+
val prefs = context.getSharedPreferences(NATIVE_VERSION_PREFS_NAME, Context.MODE_PRIVATE)
238+
prefs.edit().remove("nativeVersion").remove("nativeBuildNumber").apply()
239+
}
240+
241+
fun getBuiltinBundleVersion(context: Context): String {
242+
return try {
243+
val appInfo = context.packageManager.getApplicationInfo(context.packageName, android.content.pm.PackageManager.GET_META_DATA)
244+
appInfo.metaData?.get("BUNDLE_VERSION")?.toString() ?: ""
245+
} catch (e: Exception) {
246+
OneKeyLog.error("BundleUpdate", "Error getting builtin bundle version: ${e.message}")
247+
""
248+
}
249+
}
250+
210251
fun calculateSHA256(filePath: String): String? {
211252
return try {
212253
val digest = MessageDigest.getInstance("SHA-256")
@@ -513,6 +554,16 @@ object BundleUpdateStoreAndroid {
513554
if (currentAppVersion != prevNativeVersion) {
514555
OneKeyLog.info("BundleUpdate", "currentAppVersion is not equal to prevNativeVersion $currentAppVersion $prevNativeVersion")
515556
clearUpdateBundleData(context)
557+
clearNativeVersionPrefs(context)
558+
return null
559+
}
560+
561+
val currentBuildNumber = getBuildNumber(context)
562+
val prevBuildNumber = getNativeBuildNumber(context)
563+
if (currentBuildNumber.isNotEmpty() && prevBuildNumber.isNotEmpty() && currentBuildNumber != prevBuildNumber) {
564+
OneKeyLog.info("BundleUpdate", "buildNumber changed from $prevBuildNumber to $currentBuildNumber, clearing bundle data")
565+
clearUpdateBundleData(context)
566+
clearNativeVersionPrefs(context)
516567
return null
517568
}
518569

@@ -1008,6 +1059,8 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
10081059
BundleUpdateStoreAndroid.setCurrentBundleVersionAndSignature(context, folderName, signature)
10091060
val nativeVersion = BundleUpdateStoreAndroid.getAppVersion(context) ?: ""
10101061
BundleUpdateStoreAndroid.setNativeVersion(context, nativeVersion)
1062+
val buildNumber = BundleUpdateStoreAndroid.getBuildNumber(context)
1063+
BundleUpdateStoreAndroid.setNativeBuildNumber(context, buildNumber)
10111064

10121065
// Manage fallback data
10131066
try {
@@ -1097,6 +1150,7 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
10971150
OneKeyLog.info("BundleUpdate", "clearAllJSBundleData: deleted bundle dir")
10981151
}
10991152
BundleUpdateStoreAndroid.clearUpdateBundleData(context)
1153+
BundleUpdateStoreAndroid.clearNativeVersionPrefs(context)
11001154

11011155
OneKeyLog.info("BundleUpdate", "clearAllJSBundleData: completed successfully")
11021156
TestResult(success = true, message = "Successfully cleared all JS bundle data")
@@ -1197,6 +1251,24 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
11971251
}
11981252
}
11991253

1254+
override fun getNativeBuildNumber(): Promise<String> {
1255+
return Promise.async {
1256+
val context = getContext()
1257+
val buildNumber = BundleUpdateStoreAndroid.getBuildNumber(context)
1258+
OneKeyLog.info("BundleUpdate", "getNativeBuildNumber: $buildNumber")
1259+
buildNumber
1260+
}
1261+
}
1262+
1263+
override fun getBuiltinBundleVersion(): Promise<String> {
1264+
return Promise.async {
1265+
val context = getContext()
1266+
val version = BundleUpdateStoreAndroid.getBuiltinBundleVersion(context)
1267+
OneKeyLog.info("BundleUpdate", "getBuiltinBundleVersion: $version")
1268+
version
1269+
}
1270+
}
1271+
12001272
override fun testVerification(): Promise<Boolean> {
12011273
return Promise.async {
12021274
val testSignature = """-----BEGIN PGP SIGNED MESSAGE-----

0 commit comments

Comments
 (0)