mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-11-22 23:46:10 +08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11d40ce5f2 | ||
|
|
4a1d4d5a50 | ||
|
|
02517a9eb0 | ||
|
|
f7309f699f | ||
|
|
a224113998 | ||
|
|
f2ede92ea1 | ||
|
|
a913e8c10e | ||
|
|
c5f458291a | ||
|
|
9699632a43 | ||
|
|
80e42f5dba | ||
|
|
9b718b8f75 | ||
|
|
99e3431844 | ||
|
|
d7b5562ab7 | ||
|
|
6a0a5b2d49 | ||
|
|
7023ff57ca | ||
|
|
17e21d79cf | ||
|
|
1cab582bd0 | ||
|
|
7da5a165fd | ||
|
|
d5194a1ad1 | ||
|
|
ebc9b97e70 | ||
|
|
40742e16d8 | ||
|
|
598ae1a506 | ||
|
|
e5424591d1 | ||
|
|
2cf7336b6a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -51,3 +51,4 @@ android/bin
|
|||||||
Example/testHotUpdate/harmony
|
Example/testHotUpdate/harmony
|
||||||
Example/testHotUpdate/android/app/.cxx
|
Example/testHotUpdate/android/app/.cxx
|
||||||
Example/harmony_use_pushy/libs
|
Example/harmony_use_pushy/libs
|
||||||
|
.cursor/mcp.json
|
||||||
|
|||||||
4
Example/testHotUpdate/.gitignore
vendored
4
Example/testHotUpdate/.gitignore
vendored
@@ -62,3 +62,7 @@ buck-out/
|
|||||||
# Ruby / CocoaPods
|
# Ruby / CocoaPods
|
||||||
/ios/Pods/
|
/ios/Pods/
|
||||||
/vendor/bundle/
|
/vendor/bundle/
|
||||||
|
|
||||||
|
# react-native-update
|
||||||
|
.update
|
||||||
|
.pushy
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,14 @@
|
|||||||
#import "RCTPushy.h"
|
#import "RCTPushy.h"
|
||||||
|
|
||||||
#import <React/RCTBundleURLProvider.h>
|
#import <React/RCTBundleURLProvider.h>
|
||||||
|
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
self.moduleName = @"AwesomeProject";
|
self.moduleName = @"AwesomeProject";
|
||||||
|
self.dependencyProvider = [RCTAppDependencyProvider new];
|
||||||
// You can add your custom initial props in the dictionary below.
|
// You can add your custom initial props in the dictionary below.
|
||||||
// They will be passed down to the ViewController used by React Native.
|
// They will be passed down to the ViewController used by React Native.
|
||||||
self.initialProps = @{};
|
self.initialProps = @{};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,36 +14,36 @@
|
|||||||
"dev:harmony": "react-native bundle-harmony --dev"
|
"dev:harmony": "react-native bundle-harmony --dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": "^4.0.2",
|
"form-data": "^4.0.3",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-native": "0.78.0",
|
"react-native": "0.79.2",
|
||||||
"react-native-camera-kit": "^14.2.0",
|
"react-native-camera-kit": "^15.1.0",
|
||||||
"react-native-paper": "^5.13.1",
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-safe-area-context": "^5.3.0",
|
"react-native-safe-area-context": "^5.5.0",
|
||||||
"react-native-svg": "^15.11.2",
|
"react-native-svg": "^15.12.0",
|
||||||
"react-native-update": "^10.26.4",
|
"react-native-update": "^10.29.4",
|
||||||
"react-native-vector-icons": "^10.2.0"
|
"react-native-vector-icons": "^10.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.0",
|
"@babel/core": "^7.27.3",
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.27.2",
|
||||||
"@babel/runtime": "^7.26.0",
|
"@babel/runtime": "^7.27.3",
|
||||||
"@react-native-community/cli": "15.0.1",
|
"@react-native-community/cli": "18.0.0",
|
||||||
"@react-native-community/cli-platform-android": "15.0.1",
|
"@react-native-community/cli-platform-android": "18.0.0",
|
||||||
"@react-native-community/cli-platform-ios": "15.0.1",
|
"@react-native-community/cli-platform-ios": "18.0.0",
|
||||||
"@react-native/babel-preset": "0.78.0",
|
"@react-native/babel-preset": "0.79.2",
|
||||||
"@react-native/eslint-config": "0.78.0",
|
"@react-native/eslint-config": "0.79.2",
|
||||||
"@react-native/metro-config": "0.78.0",
|
"@react-native/metro-config": "0.79.2",
|
||||||
"@react-native/typescript-config": "0.78.0",
|
"@react-native/typescript-config": "0.79.2",
|
||||||
"@types/react": "^19.0.0",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-test-renderer": "^19.0.0",
|
"@types/react-test-renderer": "^19.0.0",
|
||||||
"detox": "^20.32.0",
|
"detox": "^20.39.0",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
"jest": "^29.6.3",
|
"jest": "^29.6.3",
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
"react-test-renderer": "19.0.0",
|
"react-test-renderer": "19.0.0",
|
||||||
"typescript": "5.8.2"
|
"typescript": "5.8.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -52,4 +52,4 @@
|
|||||||
"detox",
|
"detox",
|
||||||
"dtrace-provider"
|
"dtrace-provider"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.welcome}>欢迎使用Pushy热更新服务</Text>
|
<Text style={styles.welcome}>欢迎xxx使用Pushy热更新服务</Text>
|
||||||
<View style={{flexDirection: 'row'}}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Text>
|
<Text>
|
||||||
{useDefaultAlert ? '当前使用' : '当前不使用'}默认的alert更新提示
|
{useDefaultAlert ? '当前使用' : '当前不使用'}默认的alert更新提示
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"ios": {
|
"ios": {
|
||||||
"appId": 24794,
|
"appId": 28943,
|
||||||
"appKey": "SqShg4Klnj2hG6LAFMW2PdcgSSuniz0T"
|
"appKey": "d-OmPxIBivPrDfKhLHjxN-HS"
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"appId": 27509,
|
"appId": 27509,
|
||||||
|
|||||||
36
android/proguard.pro
vendored
36
android/proguard.pro
vendored
@@ -1,3 +1,37 @@
|
|||||||
|
# Keep our update module classes
|
||||||
-keepnames class cn.reactnative.modules.update.DownloadTask { *; }
|
-keepnames class cn.reactnative.modules.update.DownloadTask { *; }
|
||||||
-keepnames class cn.reactnative.modules.update.UpdateModuleImpl { *; }
|
-keepnames class cn.reactnative.modules.update.UpdateModuleImpl { *; }
|
||||||
-keepnames class com.facebook.react.ReactInstanceManager { *; }
|
-keepnames class cn.reactnative.modules.update.** { *; }
|
||||||
|
|
||||||
|
# Keep React Native classes
|
||||||
|
-keepnames class com.facebook.react.ReactInstanceManager { *; }
|
||||||
|
-keepnames class com.facebook.react.** { *; }
|
||||||
|
-keepnames class com.facebook.react.bridge.** { *; }
|
||||||
|
-keepnames class com.facebook.react.devsupport.** { *; }
|
||||||
|
|
||||||
|
# Keep fields used in reflection
|
||||||
|
-keepclassmembers class com.facebook.react.ReactInstanceManager {
|
||||||
|
private JSBundleLoader mBundleLoader;
|
||||||
|
private String mJSBundleFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class com.facebook.react.ReactDelegate {
|
||||||
|
private ReactHost mReactHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class com.facebook.react.ReactHost {
|
||||||
|
private boolean mUseDevSupport;
|
||||||
|
private ReactHostDelegate mReactHostDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep Expo related classes
|
||||||
|
-keepnames class expo.modules.ExpoReactHostFactory$ExpoReactHostDelegate { *; }
|
||||||
|
|
||||||
|
# Keep methods used in reflection
|
||||||
|
-keepclassmembers class com.facebook.react.ReactActivity {
|
||||||
|
public ReactDelegate getReactDelegate();
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class com.facebook.react.ReactHost {
|
||||||
|
public void reload(java.lang.String);
|
||||||
|
}
|
||||||
@@ -36,10 +36,18 @@ public class UpdateContext {
|
|||||||
this.sp = context.getSharedPreferences("update", Context.MODE_PRIVATE);
|
this.sp = context.getSharedPreferences("update", Context.MODE_PRIVATE);
|
||||||
|
|
||||||
String packageVersion = getPackageVersion();
|
String packageVersion = getPackageVersion();
|
||||||
if (!packageVersion.equals(this.sp.getString("packageVersion", null))) {
|
String buildTime = getBuildTime();
|
||||||
|
String storedPackageVersion = this.sp.getString("packageVersion", null);
|
||||||
|
String storedBuildTime = this.sp.getString("buildTime", null);
|
||||||
|
|
||||||
|
boolean packageVersionChanged = !packageVersion.equals(storedPackageVersion);
|
||||||
|
boolean buildTimeChanged = !buildTime.equals(storedBuildTime);
|
||||||
|
|
||||||
|
if (packageVersionChanged || buildTimeChanged) {
|
||||||
SharedPreferences.Editor editor = sp.edit();
|
SharedPreferences.Editor editor = sp.edit();
|
||||||
editor.clear();
|
editor.clear();
|
||||||
editor.putString("packageVersion", packageVersion);
|
editor.putString("packageVersion", packageVersion);
|
||||||
|
editor.putString("buildTime", buildTime);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|
||||||
this.cleanUp();
|
this.cleanUp();
|
||||||
@@ -169,17 +177,19 @@ public class UpdateContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void markSuccess() {
|
public void markSuccess() {
|
||||||
SharedPreferences.Editor editor = sp.edit();
|
if (!BuildConfig.DEBUG) {
|
||||||
editor.putBoolean("firstTimeOk", true);
|
SharedPreferences.Editor editor = sp.edit();
|
||||||
String lastVersion = sp.getString("lastVersion", null);
|
editor.putBoolean("firstTimeOk", true);
|
||||||
String curVersion = sp.getString("currentVersion", null);
|
String lastVersion = sp.getString("lastVersion", null);
|
||||||
if (lastVersion != null && !lastVersion.equals(curVersion)) {
|
String curVersion = sp.getString("currentVersion", null);
|
||||||
editor.remove("lastVersion");
|
if (lastVersion != null && !lastVersion.equals(curVersion)) {
|
||||||
editor.remove("hash_" + lastVersion);
|
editor.remove("lastVersion");
|
||||||
}
|
editor.remove("hash_" + lastVersion);
|
||||||
editor.apply();
|
}
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
this.cleanUp();
|
this.cleanUp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearFirstTime() {
|
public void clearFirstTime() {
|
||||||
|
|||||||
@@ -147,13 +147,22 @@ public class UpdateModuleImpl {
|
|||||||
reactHostField.setAccessible(true);
|
reactHostField.setAccessible(true);
|
||||||
Object reactHost = reactHostField.get(reactDelegate);
|
Object reactHost = reactHostField.get(reactDelegate);
|
||||||
|
|
||||||
|
Field devSupport = reactHost.getClass().getDeclaredField("mUseDevSupport");
|
||||||
|
devSupport.setAccessible(true);
|
||||||
|
devSupport.set(reactHost, false);
|
||||||
|
|
||||||
// Access the mReactHostDelegate field
|
// Access the mReactHostDelegate field
|
||||||
Field reactHostDelegateField = reactHost.getClass().getDeclaredField("mReactHostDelegate");
|
Field reactHostDelegateField = reactHost.getClass().getDeclaredField("mReactHostDelegate");
|
||||||
reactHostDelegateField.setAccessible(true);
|
reactHostDelegateField.setAccessible(true);
|
||||||
Object reactHostDelegate = reactHostDelegateField.get(reactHost);
|
Object reactHostDelegate = reactHostDelegateField.get(reactHost);
|
||||||
|
|
||||||
|
String bundleFieldName = "jsBundleLoader";
|
||||||
|
if (reactHostDelegate.getClass().getCanonicalName().equals("expo.modules.ExpoReactHostFactory.ExpoReactHostDelegate")) {
|
||||||
|
bundleFieldName = "_jsBundleLoader";
|
||||||
|
}
|
||||||
|
|
||||||
// Modify the jsBundleLoader field
|
// Modify the jsBundleLoader field
|
||||||
Field jsBundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
|
Field jsBundleLoaderField = reactHostDelegate.getClass().getDeclaredField(bundleFieldName);
|
||||||
jsBundleLoaderField.setAccessible(true);
|
jsBundleLoaderField.setAccessible(true);
|
||||||
jsBundleLoaderField.set(reactHostDelegate, loader);
|
jsBundleLoaderField.set(reactHostDelegate, loader);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import static androidx.core.content.FileProvider.getUriForFile;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import com.facebook.react.bridge.Promise;
|
import com.facebook.react.bridge.Promise;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
@@ -17,6 +19,7 @@ import java.util.Map;
|
|||||||
public class UpdateModule extends NativePushySpec {
|
public class UpdateModule extends NativePushySpec {
|
||||||
UpdateContext updateContext;
|
UpdateContext updateContext;
|
||||||
public static ReactApplicationContext mContext;
|
public static ReactApplicationContext mContext;
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
|
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
this.updateContext = updateContext;
|
this.updateContext = updateContext;
|
||||||
@@ -38,12 +41,22 @@ public class UpdateModule extends NativePushySpec {
|
|||||||
boolean isFirstTime = updateContext.isFirstTime();
|
boolean isFirstTime = updateContext.isFirstTime();
|
||||||
constants.put("isFirstTime", isFirstTime);
|
constants.put("isFirstTime", isFirstTime);
|
||||||
if (isFirstTime) {
|
if (isFirstTime) {
|
||||||
updateContext.clearFirstTime();
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateContext.clearFirstTime();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
String rolledBackVersion = updateContext.rolledBackVersion();
|
String rolledBackVersion = updateContext.rolledBackVersion();
|
||||||
constants.put("rolledBackVersion", rolledBackVersion);
|
constants.put("rolledBackVersion", rolledBackVersion);
|
||||||
if (rolledBackVersion != null) {
|
if (rolledBackVersion != null) {
|
||||||
updateContext.clearRollbackMark();
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateContext.clearRollbackMark();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
constants.put("uuid", updateContext.getKv("uuid"));
|
constants.put("uuid", updateContext.getKv("uuid"));
|
||||||
return constants;
|
return constants;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
["https://pushy-koa-qgbgqmcpis.cn-beijing.fcapp.run", "https://p.reactnative.cn/api"]
|
["https://p.reactnative.cn/api"]
|
||||||
|
|||||||
Binary file not shown.
@@ -73,7 +73,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPpk(
|
|||||||
const jsi::Value* args,
|
const jsi::Value* args,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).call(rt,"downloadPatchFromPpk", args, count));
|
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).callAsync(rt,"downloadPatchFromPpk", args, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPackage(
|
static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPackage(
|
||||||
@@ -82,7 +82,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPackage(
|
|||||||
const jsi::Value* args,
|
const jsi::Value* args,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).call(rt,"downloadPatchFromPackage", args, count));
|
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).callAsync(rt,"downloadPatchFromPackage", args, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsi::Value _hostFunction_PushyTurboModule_downloadFullUpdate(
|
static jsi::Value _hostFunction_PushyTurboModule_downloadFullUpdate(
|
||||||
@@ -91,7 +91,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadFullUpdate(
|
|||||||
const jsi::Value* args,
|
const jsi::Value* args,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).call(rt,"downloadFullUpdate", args, count));
|
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).callAsync(rt,"downloadFullUpdate", args, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsi::Value _hostFunction_PushyTurboModule_downloadAndInstallApk(
|
static jsi::Value _hostFunction_PushyTurboModule_downloadAndInstallApk(
|
||||||
@@ -100,7 +100,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadAndInstallApk(
|
|||||||
const jsi::Value* args,
|
const jsi::Value* args,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).call(rt,"downloadAndInstallApk", args, count));
|
return jsi::Value(static_cast<ArkTSTurboModule &> (turboModule).callAsync(rt,"downloadAndInstallApk", args, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class PushyFileJSBundleProvider extends JSBundleProvider {
|
|||||||
this.updateContext = new UpdateContext(context);
|
this.updateContext = new UpdateContext(context);
|
||||||
}
|
}
|
||||||
getURL(): string {
|
getURL(): string {
|
||||||
return this.updateContext.getBundleUrl();
|
return this.updateContext.getBundleUrl().substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBundle(): Promise<ArrayBuffer> {
|
async getBundle(): Promise<ArrayBuffer> {
|
||||||
|
|||||||
2
ios/ImportReact.h
Normal file
2
ios/ImportReact.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@import React;
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
static NSString *const keyPushyInfo = @"REACTNATIVECN_PUSHY_INFO_KEY";
|
static NSString *const keyPushyInfo = @"REACTNATIVECN_PUSHY_INFO_KEY";
|
||||||
static NSString *const paramPackageVersion = @"packageVersion";
|
static NSString *const paramPackageVersion = @"packageVersion";
|
||||||
|
static NSString *const paramBuildTime = @"buildTime";
|
||||||
static NSString *const paramLastVersion = @"lastVersion";
|
static NSString *const paramLastVersion = @"lastVersion";
|
||||||
static NSString *const paramCurrentVersion = @"currentVersion";
|
static NSString *const paramCurrentVersion = @"currentVersion";
|
||||||
static NSString *const paramIsFirstTime = @"isFirstTime";
|
static NSString *const paramIsFirstTime = @"isFirstTime";
|
||||||
@@ -70,20 +71,28 @@ RCT_EXPORT_MODULE(RCTPushy);
|
|||||||
{
|
{
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
|
||||||
|
// Check for version changes first
|
||||||
|
NSString *curPackageVersion = [RCTPushy packageVersion];
|
||||||
|
NSString *curBuildTime = [RCTPushy buildTime];
|
||||||
|
NSString *storedPackageVersion = [defaults stringForKey:paramPackageVersion];
|
||||||
|
NSString *storedBuildTime = [defaults stringForKey:paramBuildTime];
|
||||||
|
|
||||||
|
BOOL packageVersionChanged = ![curPackageVersion isEqualToString:storedPackageVersion];
|
||||||
|
BOOL buildTimeChanged = ![curBuildTime isEqualToString:storedBuildTime];
|
||||||
|
|
||||||
|
if (packageVersionChanged || buildTimeChanged) {
|
||||||
|
// Clear all update data and store new versions
|
||||||
|
[defaults setObject:nil forKey:keyPushyInfo];
|
||||||
|
[defaults setObject:nil forKey:keyHashInfo];
|
||||||
|
[defaults setObject:@(YES) forKey:KeyPackageUpdatedMarked];
|
||||||
|
[defaults setObject:curPackageVersion forKey:paramPackageVersion];
|
||||||
|
[defaults setObject:curBuildTime forKey:paramBuildTime];
|
||||||
|
|
||||||
|
// ...need clear files later
|
||||||
|
}
|
||||||
|
|
||||||
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
|
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
|
||||||
if (pushyInfo) {
|
if (pushyInfo) {
|
||||||
NSString *curPackageVersion = [RCTPushy packageVersion];
|
|
||||||
NSString *packageVersion = [pushyInfo objectForKey:paramPackageVersion];
|
|
||||||
|
|
||||||
BOOL needClearPushyInfo = ![curPackageVersion isEqualToString:packageVersion];
|
|
||||||
if (needClearPushyInfo) {
|
|
||||||
[defaults setObject:nil forKey:keyPushyInfo];
|
|
||||||
[defaults setObject:nil forKey:keyHashInfo];
|
|
||||||
[defaults setObject:@(YES) forKey:KeyPackageUpdatedMarked];
|
|
||||||
|
|
||||||
// ...need clear files later
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSString *curVersion = pushyInfo[paramCurrentVersion];
|
NSString *curVersion = pushyInfo[paramCurrentVersion];
|
||||||
|
|
||||||
BOOL isFirstTime = [pushyInfo[paramIsFirstTime] boolValue];
|
BOOL isFirstTime = [pushyInfo[paramIsFirstTime] boolValue];
|
||||||
@@ -93,8 +102,7 @@ RCT_EXPORT_MODULE(RCTPushy);
|
|||||||
BOOL needRollback = (!ignoreRollback && isFirstTime == NO && isFirstLoadOK == NO) || loadVersion.length<=0;
|
BOOL needRollback = (!ignoreRollback && isFirstTime == NO && isFirstLoadOK == NO) || loadVersion.length<=0;
|
||||||
if (needRollback) {
|
if (needRollback) {
|
||||||
loadVersion = [self rollback];
|
loadVersion = [self rollback];
|
||||||
}
|
} else if (isFirstTime && !ignoreRollback){
|
||||||
else if (isFirstTime && !ignoreRollback){
|
|
||||||
// bundleURL may be called many times, ignore rollbacks before process restarted again.
|
// bundleURL may be called many times, ignore rollbacks before process restarted again.
|
||||||
ignoreRollback = true;
|
ignoreRollback = true;
|
||||||
|
|
||||||
@@ -116,7 +124,6 @@ RCT_EXPORT_MODULE(RCTPushy);
|
|||||||
loadVersion = [self rollback];
|
loadVersion = [self rollback];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [RCTPushy binaryBundleURL];
|
return [RCTPushy binaryBundleURL];
|
||||||
@@ -128,13 +135,11 @@ RCT_EXPORT_MODULE(RCTPushy);
|
|||||||
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
|
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
|
||||||
NSString *lastVersion = pushyInfo[paramLastVersion];
|
NSString *lastVersion = pushyInfo[paramLastVersion];
|
||||||
NSString *curVersion = pushyInfo[paramCurrentVersion];
|
NSString *curVersion = pushyInfo[paramCurrentVersion];
|
||||||
NSString *curPackageVersion = [RCTPushy packageVersion];
|
|
||||||
if (lastVersion.length) {
|
if (lastVersion.length) {
|
||||||
// roll back to last version
|
// roll back to last version
|
||||||
[defaults setObject:@{paramCurrentVersion:lastVersion,
|
[defaults setObject:@{paramCurrentVersion:lastVersion,
|
||||||
paramIsFirstTime:@(NO),
|
paramIsFirstTime:@(NO),
|
||||||
paramIsFirstLoadOk:@(YES),
|
paramIsFirstLoadOk:@(YES)}
|
||||||
paramPackageVersion:curPackageVersion}
|
|
||||||
forKey:keyPushyInfo];
|
forKey:keyPushyInfo];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -297,39 +302,38 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options
|
|||||||
newInfo[paramLastVersion] = lastVersion;
|
newInfo[paramLastVersion] = lastVersion;
|
||||||
newInfo[paramIsFirstTime] = @(YES);
|
newInfo[paramIsFirstTime] = @(YES);
|
||||||
newInfo[paramIsFirstLoadOk] = @(NO);
|
newInfo[paramIsFirstLoadOk] = @(NO);
|
||||||
newInfo[paramPackageVersion] = [RCTPushy packageVersion];
|
|
||||||
[defaults setObject:newInfo forKey:keyPushyInfo];
|
[defaults setObject:newInfo forKey:keyPushyInfo];
|
||||||
|
|
||||||
|
|
||||||
resolve(@true);
|
resolve(@true);
|
||||||
}else{
|
} else {
|
||||||
reject(@"执行报错", nil, nil);
|
reject(@"执行报错", nil, nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
|
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
|
||||||
resolver:(RCTPromiseResolveBlock)resolve
|
resolver:(RCTPromiseResolveBlock)resolve
|
||||||
rejecter:(RCTPromiseRejectBlock)reject)
|
rejecter:(RCTPromiseRejectBlock)reject)
|
||||||
{
|
{
|
||||||
@try {
|
@try {
|
||||||
NSString *hash = options[@"hash"];
|
NSString *hash = options[@"hash"];
|
||||||
if (hash.length) {
|
if (hash.length) {
|
||||||
[self setNeedUpdate:options resolver:resolve rejecter:reject];
|
// 只在 setNeedUpdate 成功后 resolve
|
||||||
|
[self setNeedUpdate:options resolver:^(id result) {
|
||||||
// reload in earlier version
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
#if __has_include("RCTReloadCommand.h")
|
||||||
[self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
|
// reload 0.62+
|
||||||
[self.bridge reload];
|
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
||||||
});
|
RCTTriggerReloadCommandListeners(@"pushy reloadUpdate");
|
||||||
|
#else
|
||||||
#if __has_include("RCTReloadCommand.h")
|
[self.bridge reload];
|
||||||
// reload 0.62+
|
#endif
|
||||||
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
});
|
||||||
RCTTriggerReloadCommandListeners(@"pushy reload");
|
resolve(@true);
|
||||||
#endif
|
} rejecter:^(NSString *code, NSString *message, NSError *error) {
|
||||||
|
reject(code, message, error);
|
||||||
resolve(@true);
|
}];
|
||||||
}else{
|
} else {
|
||||||
reject(@"执行报错", nil, nil);
|
reject(@"执行报错", nil, nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,13 +347,14 @@ RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
|
|||||||
{
|
{
|
||||||
@try {
|
@try {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self.bridge reload];
|
#if __has_include("RCTReloadCommand.h")
|
||||||
|
// reload 0.62+
|
||||||
|
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
||||||
|
RCTTriggerReloadCommandListeners(@"pushy restartApp");
|
||||||
|
#else
|
||||||
|
[self.bridge reload];
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
#if __has_include("RCTReloadCommand.h")
|
|
||||||
// reload 0.62+
|
|
||||||
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
|
||||||
RCTTriggerReloadCommandListeners(@"pushy restartApp");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
resolve(@true);
|
resolve(@true);
|
||||||
}
|
}
|
||||||
@@ -361,6 +366,9 @@ RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
|
|||||||
RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
|
RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
|
||||||
rejecter:(RCTPromiseRejectBlock)reject)
|
rejecter:(RCTPromiseRejectBlock)reject)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
resolve(@true);
|
||||||
|
#else
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
// up package info
|
// up package info
|
||||||
@@ -384,6 +392,7 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
|
|||||||
@catch (NSException *exception) {
|
@catch (NSException *exception) {
|
||||||
reject(@"执行报错", nil, nil);
|
reject(@"执行报错", nil, nil);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -542,7 +551,15 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
|
|||||||
callback([self errorWithMessage:ERROR_HDIFFPATCH]);
|
callback([self errorWithMessage:ERROR_HDIFFPATCH]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
[_fileManager hdiffFileAtPath:bundlePatch fromOrigin:bundleOrigin toDestination:destination completionHandler:completionHandler];
|
|
||||||
|
@try {
|
||||||
|
[_fileManager hdiffFileAtPath:bundlePatch fromOrigin:bundleOrigin toDestination:destination completionHandler:completionHandler];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
NSLog(@"Pushy _dopatch error: exception occurred during hdiffFileAtPath: %@, reason: %@",
|
||||||
|
exception.name, exception.reason);
|
||||||
|
callback([self errorWithMessage:ERROR_HDIFFPATCH]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)patch:(NSString *)hash fromBundle:(NSString *)bundleOrigin source:(NSString *)sourceOrigin callback:(void (^)(NSError *error))callback
|
- (void)patch:(NSString *)hash fromBundle:(NSString *)bundleOrigin source:(NSString *)sourceOrigin callback:(void (^)(NSError *error))callback
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-update",
|
"name": "react-native-update",
|
||||||
"version": "10.28.11",
|
"version": "10.30.3",
|
||||||
"description": "react-native hot update",
|
"description": "react-native hot update",
|
||||||
"main": "src/index",
|
"main": "src/index",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -90,13 +90,6 @@ Pod::Spec.new do |s|
|
|||||||
|
|
||||||
s.source = { :git => 'https://github.com/reactnativecn/react-native-update.git', :tag => '#{s.version}' }
|
s.source = { :git => 'https://github.com/reactnativecn/react-native-update.git', :tag => '#{s.version}' }
|
||||||
|
|
||||||
# Conditionally set source files
|
|
||||||
if valid_expo_project
|
|
||||||
s.source_files = Dir.glob("ios/**/*.{h,m,mm,swift}") # Include Expo files
|
|
||||||
else
|
|
||||||
s.source_files = Dir.glob("ios/**/*.{h,m,mm,swift}").reject { |f| f.start_with?("ios/Expo/") } # Exclude Expo files
|
|
||||||
end
|
|
||||||
|
|
||||||
s.libraries = 'bz2', 'z'
|
s.libraries = 'bz2', 'z'
|
||||||
s.vendored_libraries = 'RCTPushy/libRCTPushy.a'
|
s.vendored_libraries = 'RCTPushy/libRCTPushy.a'
|
||||||
s.pod_target_xcconfig = {
|
s.pod_target_xcconfig = {
|
||||||
@@ -112,22 +105,18 @@ Pod::Spec.new do |s|
|
|||||||
|
|
||||||
# Conditionally add Expo dependency
|
# Conditionally add Expo dependency
|
||||||
if valid_expo_project
|
if valid_expo_project
|
||||||
|
s.public_header_files = ['ios/ImportReact.h']
|
||||||
s.dependency 'ExpoModulesCore'
|
s.dependency 'ExpoModulesCore'
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTPushy' do |ss|
|
s.subspec 'RCTPushy' do |ss|
|
||||||
ss.source_files = 'ios/RCTPushy/*.{h,m,mm,swift}'
|
ss.source_files = ['ios/RCTPushy/**/*.{h,m,mm,c}',
|
||||||
ss.public_header_files = ['ios/RCTPushy/*.h']
|
|
||||||
end
|
|
||||||
|
|
||||||
s.subspec 'HDiffPatch' do |ss|
|
|
||||||
ss.source_files = ['ios/RCTPushy/HDiffPatch/**/*.{h,m,c}',
|
|
||||||
'android/jni/hpatch.{h,c}',
|
'android/jni/hpatch.{h,c}',
|
||||||
'android/jni/HDiffPatch/libHDiffPatch/HPatch/*.{h,c}',
|
'android/jni/HDiffPatch/libHDiffPatch/HPatch/*.{h,c}',
|
||||||
'android/jni/HDiffPatch/file_for_patch.{h,c}',
|
'android/jni/HDiffPatch/file_for_patch.{h,c}',
|
||||||
'android/jni/lzma/C/LzmaDec.{h,c}',
|
'android/jni/lzma/C/LzmaDec.{h,c}',
|
||||||
'android/jni/lzma/C/Lzma2Dec.{h,c}']
|
'android/jni/lzma/C/Lzma2Dec.{h,c}']
|
||||||
ss.public_header_files = 'ios/RCTPushy/HDiffPatch/**/*.h'
|
ss.public_header_files = ['ios/RCTPushy/**/*.h']
|
||||||
end
|
end
|
||||||
|
|
||||||
# Conditionally add Expo subspec and check ExpoModulesCore version
|
# Conditionally add Expo subspec and check ExpoModulesCore version
|
||||||
|
|||||||
143
src/client.ts
143
src/client.ts
@@ -1,33 +1,33 @@
|
|||||||
import { CheckResult, ClientOptions, ProgressData, EventType } from './type';
|
|
||||||
import {
|
import {
|
||||||
assertDev,
|
DeviceEventEmitter,
|
||||||
|
EmitterSubscription,
|
||||||
|
Platform,
|
||||||
|
} from 'react-native';
|
||||||
|
import {
|
||||||
|
PushyModule,
|
||||||
|
buildTime,
|
||||||
|
cInfo,
|
||||||
|
currentVersion,
|
||||||
|
getCurrentVersionInfo,
|
||||||
|
isFirstTime,
|
||||||
|
isRolledBack,
|
||||||
|
packageVersion,
|
||||||
|
pushyNativeEventEmitter,
|
||||||
|
rolledBackVersion,
|
||||||
|
setLocalHashInfo,
|
||||||
|
} from './core';
|
||||||
|
import { PermissionsAndroid } from './permissions';
|
||||||
|
import { CheckResult, ClientOptions, EventType, ProgressData } from './type';
|
||||||
|
import {
|
||||||
assertWeb,
|
assertWeb,
|
||||||
emptyObj,
|
emptyObj,
|
||||||
|
enhancedFetch,
|
||||||
joinUrls,
|
joinUrls,
|
||||||
log,
|
log,
|
||||||
noop,
|
noop,
|
||||||
promiseAny,
|
promiseAny,
|
||||||
testUrls,
|
testUrls,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import {
|
|
||||||
EmitterSubscription,
|
|
||||||
Platform,
|
|
||||||
DeviceEventEmitter,
|
|
||||||
} from 'react-native';
|
|
||||||
import { PermissionsAndroid } from './permissions';
|
|
||||||
import {
|
|
||||||
PushyModule,
|
|
||||||
buildTime,
|
|
||||||
cInfo,
|
|
||||||
pushyNativeEventEmitter,
|
|
||||||
currentVersion,
|
|
||||||
packageVersion,
|
|
||||||
rolledBackVersion,
|
|
||||||
setLocalHashInfo,
|
|
||||||
isFirstTime,
|
|
||||||
isRolledBack,
|
|
||||||
getCurrentVersionInfo,
|
|
||||||
} from './core';
|
|
||||||
|
|
||||||
const SERVER_PRESETS = {
|
const SERVER_PRESETS = {
|
||||||
// cn
|
// cn
|
||||||
@@ -148,6 +148,7 @@ export class Pushy {
|
|||||||
await this.loggerPromise.promise;
|
await this.loggerPromise.promise;
|
||||||
const { logger = noop, appKey } = this.options;
|
const { logger = noop, appKey } = this.options;
|
||||||
const info = await getCurrentVersionInfo();
|
const info = await getCurrentVersionInfo();
|
||||||
|
const overridePackageVersion = this.options.overridePackageVersion;
|
||||||
logger({
|
logger({
|
||||||
type,
|
type,
|
||||||
data: {
|
data: {
|
||||||
@@ -155,6 +156,7 @@ export class Pushy {
|
|||||||
currentVersion,
|
currentVersion,
|
||||||
cInfo,
|
cInfo,
|
||||||
packageVersion,
|
packageVersion,
|
||||||
|
overridePackageVersion,
|
||||||
buildTime,
|
buildTime,
|
||||||
message,
|
message,
|
||||||
...info,
|
...info,
|
||||||
@@ -170,10 +172,12 @@ export class Pushy {
|
|||||||
getCheckUrl = (endpoint: string = this.options.server!.main) => {
|
getCheckUrl = (endpoint: string = this.options.server!.main) => {
|
||||||
return `${endpoint}/checkUpdate/${this.options.appKey}`;
|
return `${endpoint}/checkUpdate/${this.options.appKey}`;
|
||||||
};
|
};
|
||||||
assertDebug = () => {
|
assertDebug = (matter: string) => {
|
||||||
if (__DEV__ && !this.options.debug) {
|
if (__DEV__ && !this.options.debug) {
|
||||||
console.info(
|
console.info(
|
||||||
'You are currently in the development environment and have not enabled debug mode. The hot update check will not be performed. If you need to debug hot updates in the development environment, please set debug to true in the client.',
|
`You are currently in the development environment and have not enabled debug mode.
|
||||||
|
${matter} will not be performed.
|
||||||
|
If you need to debug ${matter} in the development environment, please set debug to true in the client.`,
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -188,7 +192,7 @@ export class Pushy {
|
|||||||
this.report({ type: 'markSuccess' });
|
this.report({ type: 'markSuccess' });
|
||||||
};
|
};
|
||||||
switchVersion = async (hash: string) => {
|
switchVersion = async (hash: string) => {
|
||||||
if (!assertDev('switchVersion()')) {
|
if (!this.assertDebug('switchVersion()')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (assertHash(hash) && !sharedState.applyingUpdate) {
|
if (assertHash(hash) && !sharedState.applyingUpdate) {
|
||||||
@@ -199,7 +203,7 @@ export class Pushy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
switchVersionLater = async (hash: string) => {
|
switchVersionLater = async (hash: string) => {
|
||||||
if (!assertDev('switchVersionLater()')) {
|
if (!this.assertDebug('switchVersionLater()')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (assertHash(hash)) {
|
if (assertHash(hash)) {
|
||||||
@@ -208,7 +212,7 @@ export class Pushy {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
checkUpdate = async (extra?: Record<string, any>) => {
|
checkUpdate = async (extra?: Record<string, any>) => {
|
||||||
if (!this.assertDebug()) {
|
if (!this.assertDebug('checkUpdate()')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!assertWeb()) {
|
if (!assertWeb()) {
|
||||||
@@ -231,7 +235,7 @@ export class Pushy {
|
|||||||
}
|
}
|
||||||
this.lastChecking = now;
|
this.lastChecking = now;
|
||||||
const fetchBody = {
|
const fetchBody = {
|
||||||
packageVersion,
|
packageVersion: this.options.overridePackageVersion || packageVersion,
|
||||||
hash: currentVersion,
|
hash: currentVersion,
|
||||||
buildTime,
|
buildTime,
|
||||||
cInfo,
|
cInfo,
|
||||||
@@ -261,7 +265,7 @@ export class Pushy {
|
|||||||
type: 'checking',
|
type: 'checking',
|
||||||
message: this.options.appKey + ': ' + stringifyBody,
|
message: this.options.appKey + ': ' + stringifyBody,
|
||||||
});
|
});
|
||||||
resp = await fetch(this.getCheckUrl(), fetchPayload);
|
resp = await enhancedFetch(this.getCheckUrl(), fetchPayload);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.report({
|
this.report({
|
||||||
type: 'errorChecking',
|
type: 'errorChecking',
|
||||||
@@ -272,7 +276,7 @@ export class Pushy {
|
|||||||
try {
|
try {
|
||||||
resp = await promiseAny(
|
resp = await promiseAny(
|
||||||
backupEndpoints.map(endpoint =>
|
backupEndpoints.map(endpoint =>
|
||||||
fetch(this.getCheckUrl(endpoint), fetchPayload),
|
enhancedFetch(this.getCheckUrl(endpoint), fetchPayload),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -389,11 +393,16 @@ export class Pushy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let succeeded = '';
|
let succeeded = '';
|
||||||
this.report({ type: 'downloading' });
|
this.report({
|
||||||
|
type: 'downloading',
|
||||||
|
data: {
|
||||||
|
newVersion: hash,
|
||||||
|
},
|
||||||
|
});
|
||||||
let lastError: any;
|
let lastError: any;
|
||||||
let errorMessages: string[] = [];
|
let errorMessages: string[] = [];
|
||||||
const diffUrl = await testUrls(joinUrls(paths, diff));
|
const diffUrl = await testUrls(joinUrls(paths, diff));
|
||||||
if (diffUrl) {
|
if (diffUrl && !__DEV__) {
|
||||||
log('downloading diff');
|
log('downloading diff');
|
||||||
try {
|
try {
|
||||||
await PushyModule.downloadPatchFromPpk({
|
await PushyModule.downloadPatchFromPpk({
|
||||||
@@ -406,60 +415,56 @@ export class Pushy {
|
|||||||
const errorMessage = `diff error: ${e.message}`;
|
const errorMessage = `diff error: ${e.message}`;
|
||||||
errorMessages.push(errorMessage);
|
errorMessages.push(errorMessage);
|
||||||
lastError = new Error(errorMessage);
|
lastError = new Error(errorMessage);
|
||||||
if (__DEV__) {
|
log(errorMessage);
|
||||||
succeeded = 'diff';
|
|
||||||
} else {
|
|
||||||
log(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const pdiffUrl = await testUrls(joinUrls(paths, pdiff));
|
if (!succeeded) {
|
||||||
if (!succeeded && pdiffUrl) {
|
const pdiffUrl = await testUrls(joinUrls(paths, pdiff));
|
||||||
log('downloading pdiff');
|
if (pdiffUrl && !__DEV__) {
|
||||||
try {
|
log('downloading pdiff');
|
||||||
await PushyModule.downloadPatchFromPackage({
|
try {
|
||||||
updateUrl: pdiffUrl,
|
await PushyModule.downloadPatchFromPackage({
|
||||||
hash,
|
updateUrl: pdiffUrl,
|
||||||
});
|
hash,
|
||||||
succeeded = 'pdiff';
|
});
|
||||||
} catch (e: any) {
|
|
||||||
const errorMessage = `pdiff error: ${e.message}`;
|
|
||||||
errorMessages.push(errorMessage);
|
|
||||||
lastError = new Error(errorMessage);
|
|
||||||
if (__DEV__) {
|
|
||||||
succeeded = 'pdiff';
|
succeeded = 'pdiff';
|
||||||
} else {
|
} catch (e: any) {
|
||||||
|
const errorMessage = `pdiff error: ${e.message}`;
|
||||||
|
errorMessages.push(errorMessage);
|
||||||
|
lastError = new Error(errorMessage);
|
||||||
log(errorMessage);
|
log(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fullUrl = await testUrls(joinUrls(paths, full));
|
if (!succeeded) {
|
||||||
if (!succeeded && fullUrl) {
|
const fullUrl = await testUrls(joinUrls(paths, full));
|
||||||
log('downloading full patch');
|
if (fullUrl) {
|
||||||
try {
|
log('downloading full patch');
|
||||||
await PushyModule.downloadFullUpdate({
|
try {
|
||||||
updateUrl: fullUrl,
|
await PushyModule.downloadFullUpdate({
|
||||||
hash,
|
updateUrl: fullUrl,
|
||||||
});
|
hash,
|
||||||
succeeded = 'full';
|
});
|
||||||
} catch (e: any) {
|
|
||||||
const errorMessage = `full patch error: ${e.message}`;
|
|
||||||
errorMessages.push(errorMessage);
|
|
||||||
lastError = new Error(errorMessage);
|
|
||||||
if (__DEV__) {
|
|
||||||
succeeded = 'full';
|
succeeded = 'full';
|
||||||
} else {
|
} catch (e: any) {
|
||||||
|
const errorMessage = `full patch error: ${e.message}`;
|
||||||
|
errorMessages.push(errorMessage);
|
||||||
|
lastError = new Error(errorMessage);
|
||||||
log(errorMessage);
|
log(errorMessage);
|
||||||
}
|
}
|
||||||
|
} else if (__DEV__) {
|
||||||
|
log(
|
||||||
|
`当前是开发环境,无法执行增量式热更新,重启不会生效。
|
||||||
|
如果需要在开发环境中测试可生效的全量热更新(但也会在再次重启后重新连接 metro),
|
||||||
|
请打开“忽略时间戳”开关再重试。`,
|
||||||
|
);
|
||||||
|
succeeded = 'full';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sharedState.progressHandlers[hash]) {
|
if (sharedState.progressHandlers[hash]) {
|
||||||
sharedState.progressHandlers[hash].remove();
|
sharedState.progressHandlers[hash].remove();
|
||||||
delete sharedState.progressHandlers[hash];
|
delete sharedState.progressHandlers[hash];
|
||||||
}
|
}
|
||||||
if (__DEV__) {
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
this.report({
|
this.report({
|
||||||
type: 'errorUpdate',
|
type: 'errorUpdate',
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ export const UpdateProvider = ({
|
|||||||
const markSuccess = client.markSuccess;
|
const markSuccess = client.markSuccess;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!client.assertDebug()) {
|
if (!client.assertDebug('checkUpdate()')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { checkStrategy, dismissErrorAfter, autoMarkSuccess } = options;
|
const { checkStrategy, dismissErrorAfter, autoMarkSuccess } = options;
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export interface ClientOptions {
|
|||||||
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
||||||
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
||||||
onPackageExpired?: (info: CheckResult) => Promise<boolean>;
|
onPackageExpired?: (info: CheckResult) => Promise<boolean>;
|
||||||
|
overridePackageVersion?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateTestPayload {
|
export interface UpdateTestPayload {
|
||||||
|
|||||||
42
src/utils.ts
42
src/utils.ts
@@ -40,13 +40,13 @@ const ping =
|
|||||||
: async (url: string) => {
|
: async (url: string) => {
|
||||||
let pingFinished = false;
|
let pingFinished = false;
|
||||||
return Promise.race([
|
return Promise.race([
|
||||||
fetch(url, {
|
enhancedFetch(url, {
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
})
|
})
|
||||||
.then(({ status, statusText }) => {
|
.then(({ status, statusText, url: finalUrl }) => {
|
||||||
pingFinished = true;
|
pingFinished = true;
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
return url;
|
return finalUrl;
|
||||||
}
|
}
|
||||||
log('ping failed', url, status, statusText);
|
log('ping failed', url, status, statusText);
|
||||||
throw new Error('Ping failed');
|
throw new Error('Ping failed');
|
||||||
@@ -69,7 +69,7 @@ const ping =
|
|||||||
|
|
||||||
export function joinUrls(paths: string[], fileName?: string) {
|
export function joinUrls(paths: string[], fileName?: string) {
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
return paths.map(path => 'https://' + path + '/' + fileName);
|
return paths.map(path => `https://${path}/${fileName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +99,30 @@ export const assertWeb = () => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const assertDev = (matter: string) => {
|
// export const isAndroid70AndBelow = () => {
|
||||||
if (__DEV__) {
|
// // android 7.0 and below devices do not support letsencrypt cert
|
||||||
console.warn(
|
// // https://letsencrypt.org/2023/07/10/cross-sign-expiration/
|
||||||
`${matter} is not supported in development environment; no action taken.`,
|
// return Platform.OS === 'android' && Platform.Version <= 24;
|
||||||
);
|
// };
|
||||||
return false;
|
|
||||||
}
|
export const enhancedFetch = async (
|
||||||
return true;
|
url: string,
|
||||||
|
params: Parameters<typeof fetch>[1],
|
||||||
|
isRetry = false,
|
||||||
|
): Promise<Response> => {
|
||||||
|
return fetch(url, params)
|
||||||
|
.then(r => {
|
||||||
|
if (r.ok) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
throw new Error(`${r.status} ${r.statusText}`);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
log('fetch error', url, e);
|
||||||
|
if (isRetry) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log('trying fallback to http');
|
||||||
|
return enhancedFetch(url.replace('https', 'http'), params, true);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user