mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-09-16 13:01:38 +08:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9b718b8f75 | ||
![]() |
99e3431844 | ||
![]() |
d7b5562ab7 | ||
![]() |
6a0a5b2d49 | ||
![]() |
7023ff57ca | ||
![]() |
17e21d79cf | ||
![]() |
1cab582bd0 | ||
![]() |
7da5a165fd | ||
![]() |
d5194a1ad1 | ||
![]() |
ebc9b97e70 | ||
![]() |
40742e16d8 | ||
![]() |
598ae1a506 | ||
![]() |
e5424591d1 | ||
![]() |
2cf7336b6a |
4
Example/testHotUpdate/.gitignore
vendored
4
Example/testHotUpdate/.gitignore
vendored
@@ -62,3 +62,7 @@ buck-out/
|
||||
# Ruby / CocoaPods
|
||||
/ios/Pods/
|
||||
/vendor/bundle/
|
||||
|
||||
# react-native-update
|
||||
.update
|
||||
.pushy
|
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
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
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,14 @@
|
||||
#import "RCTPushy.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.moduleName = @"AwesomeProject";
|
||||
self.dependencyProvider = [RCTAppDependencyProvider new];
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -14,36 +14,36 @@
|
||||
"dev:harmony": "react-native bundle-harmony --dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": "^4.0.2",
|
||||
"form-data": "^4.0.3",
|
||||
"patch-package": "^8.0.0",
|
||||
"react": "19.0.0",
|
||||
"react-native": "0.78.0",
|
||||
"react-native-camera-kit": "^14.2.0",
|
||||
"react-native-paper": "^5.13.1",
|
||||
"react-native-safe-area-context": "^5.3.0",
|
||||
"react-native-svg": "^15.11.2",
|
||||
"react-native-update": "^10.26.4",
|
||||
"react-native": "0.79.2",
|
||||
"react-native-camera-kit": "^15.1.0",
|
||||
"react-native-paper": "^5.14.5",
|
||||
"react-native-safe-area-context": "^5.5.0",
|
||||
"react-native-svg": "^15.12.0",
|
||||
"react-native-update": "^10.29.4",
|
||||
"react-native-vector-icons": "^10.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@react-native-community/cli": "15.0.1",
|
||||
"@react-native-community/cli-platform-android": "15.0.1",
|
||||
"@react-native-community/cli-platform-ios": "15.0.1",
|
||||
"@react-native/babel-preset": "0.78.0",
|
||||
"@react-native/eslint-config": "0.78.0",
|
||||
"@react-native/metro-config": "0.78.0",
|
||||
"@react-native/typescript-config": "0.78.0",
|
||||
"@babel/core": "^7.27.3",
|
||||
"@babel/preset-env": "^7.27.2",
|
||||
"@babel/runtime": "^7.27.3",
|
||||
"@react-native-community/cli": "18.0.0",
|
||||
"@react-native-community/cli-platform-android": "18.0.0",
|
||||
"@react-native-community/cli-platform-ios": "18.0.0",
|
||||
"@react-native/babel-preset": "0.79.2",
|
||||
"@react-native/eslint-config": "0.79.2",
|
||||
"@react-native/metro-config": "0.79.2",
|
||||
"@react-native/typescript-config": "0.79.2",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-test-renderer": "^19.0.0",
|
||||
"detox": "^20.32.0",
|
||||
"detox": "^20.39.0",
|
||||
"eslint": "^8.19.0",
|
||||
"jest": "^29.6.3",
|
||||
"prettier": "2.8.8",
|
||||
"react-test-renderer": "19.0.0",
|
||||
"typescript": "5.8.2"
|
||||
"typescript": "5.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -52,4 +52,4 @@
|
||||
"detox",
|
||||
"dtrace-provider"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ios": {
|
||||
"appId": 24794,
|
||||
"appKey": "SqShg4Klnj2hG6LAFMW2PdcgSSuniz0T"
|
||||
"appId": 28943,
|
||||
"appKey": "d-OmPxIBivPrDfKhLHjxN-HS"
|
||||
},
|
||||
"android": {
|
||||
"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.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);
|
||||
}
|
@@ -169,17 +169,19 @@ public class UpdateContext {
|
||||
}
|
||||
|
||||
public void markSuccess() {
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putBoolean("firstTimeOk", true);
|
||||
String lastVersion = sp.getString("lastVersion", null);
|
||||
String curVersion = sp.getString("currentVersion", null);
|
||||
if (lastVersion != null && !lastVersion.equals(curVersion)) {
|
||||
editor.remove("lastVersion");
|
||||
editor.remove("hash_" + lastVersion);
|
||||
}
|
||||
editor.apply();
|
||||
if (!BuildConfig.DEBUG) {
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putBoolean("firstTimeOk", true);
|
||||
String lastVersion = sp.getString("lastVersion", null);
|
||||
String curVersion = sp.getString("currentVersion", null);
|
||||
if (lastVersion != null && !lastVersion.equals(curVersion)) {
|
||||
editor.remove("lastVersion");
|
||||
editor.remove("hash_" + lastVersion);
|
||||
}
|
||||
editor.apply();
|
||||
|
||||
this.cleanUp();
|
||||
this.cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearFirstTime() {
|
||||
|
@@ -147,13 +147,22 @@ public class UpdateModuleImpl {
|
||||
reactHostField.setAccessible(true);
|
||||
Object reactHost = reactHostField.get(reactDelegate);
|
||||
|
||||
Field devSupport = reactHost.getClass().getDeclaredField("mUseDevSupport");
|
||||
devSupport.setAccessible(true);
|
||||
devSupport.set(reactHost, false);
|
||||
|
||||
// Access the mReactHostDelegate field
|
||||
Field reactHostDelegateField = reactHost.getClass().getDeclaredField("mReactHostDelegate");
|
||||
reactHostDelegateField.setAccessible(true);
|
||||
Object reactHostDelegate = reactHostDelegateField.get(reactHost);
|
||||
|
||||
String bundleFieldName = "jsBundleLoader";
|
||||
if (reactHostDelegate.getClass().getCanonicalName().equals("expo.modules.ExpoReactHostFactory.ExpoReactHostDelegate")) {
|
||||
bundleFieldName = "_jsBundleLoader";
|
||||
}
|
||||
|
||||
// Modify the jsBundleLoader field
|
||||
Field jsBundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
|
||||
Field jsBundleLoaderField = reactHostDelegate.getClass().getDeclaredField(bundleFieldName);
|
||||
jsBundleLoaderField.setAccessible(true);
|
||||
jsBundleLoaderField.set(reactHostDelegate, loader);
|
||||
|
||||
|
@@ -4,6 +4,8 @@ import static androidx.core.content.FileProvider.getUriForFile;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
@@ -17,6 +19,7 @@ import java.util.Map;
|
||||
public class UpdateModule extends NativePushySpec {
|
||||
UpdateContext updateContext;
|
||||
public static ReactApplicationContext mContext;
|
||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
|
||||
super(reactContext);
|
||||
this.updateContext = updateContext;
|
||||
@@ -38,12 +41,22 @@ public class UpdateModule extends NativePushySpec {
|
||||
boolean isFirstTime = updateContext.isFirstTime();
|
||||
constants.put("isFirstTime", isFirstTime);
|
||||
if (isFirstTime) {
|
||||
updateContext.clearFirstTime();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateContext.clearFirstTime();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
String rolledBackVersion = updateContext.rolledBackVersion();
|
||||
constants.put("rolledBackVersion", rolledBackVersion);
|
||||
if (rolledBackVersion != null) {
|
||||
updateContext.clearRollbackMark();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateContext.clearRollbackMark();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
constants.put("uuid", updateContext.getKv("uuid"));
|
||||
return constants;
|
||||
|
Binary file not shown.
@@ -73,7 +73,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPpk(
|
||||
const jsi::Value* args,
|
||||
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(
|
||||
@@ -82,7 +82,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadPatchFromPackage(
|
||||
const jsi::Value* args,
|
||||
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(
|
||||
@@ -91,7 +91,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadFullUpdate(
|
||||
const jsi::Value* args,
|
||||
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(
|
||||
@@ -100,7 +100,7 @@ static jsi::Value _hostFunction_PushyTurboModule_downloadAndInstallApk(
|
||||
const jsi::Value* args,
|
||||
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);
|
||||
}
|
||||
getURL(): string {
|
||||
return this.updateContext.getBundleUrl();
|
||||
return this.updateContext.getBundleUrl().substring(1);
|
||||
}
|
||||
|
||||
async getBundle(): Promise<ArrayBuffer> {
|
||||
|
2
ios/ImportReact.h
Normal file
2
ios/ImportReact.h
Normal file
@@ -0,0 +1,2 @@
|
||||
@import React;
|
||||
|
@@ -93,8 +93,7 @@ RCT_EXPORT_MODULE(RCTPushy);
|
||||
BOOL needRollback = (!ignoreRollback && isFirstTime == NO && isFirstLoadOK == NO) || loadVersion.length<=0;
|
||||
if (needRollback) {
|
||||
loadVersion = [self rollback];
|
||||
}
|
||||
else if (isFirstTime && !ignoreRollback){
|
||||
} else if (isFirstTime && !ignoreRollback){
|
||||
// bundleURL may be called many times, ignore rollbacks before process restarted again.
|
||||
ignoreRollback = true;
|
||||
|
||||
@@ -302,34 +301,34 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options
|
||||
|
||||
|
||||
resolve(@true);
|
||||
}else{
|
||||
} else {
|
||||
reject(@"执行报错", nil, nil);
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
@try {
|
||||
NSString *hash = options[@"hash"];
|
||||
if (hash.length) {
|
||||
[self setNeedUpdate:options resolver:resolve rejecter:reject];
|
||||
|
||||
// reload in earlier version
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
|
||||
[self.bridge reload];
|
||||
});
|
||||
|
||||
#if __has_include("RCTReloadCommand.h")
|
||||
// reload 0.62+
|
||||
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
||||
RCTTriggerReloadCommandListeners(@"pushy reload");
|
||||
#endif
|
||||
|
||||
resolve(@true);
|
||||
}else{
|
||||
// 只在 setNeedUpdate 成功后 resolve
|
||||
[self setNeedUpdate:options resolver:^(id result) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#if __has_include("RCTReloadCommand.h")
|
||||
// reload 0.62+
|
||||
RCTReloadCommandSetBundleURL([[self class] bundleURL]);
|
||||
RCTTriggerReloadCommandListeners(@"pushy reloadUpdate");
|
||||
#else
|
||||
[self.bridge reload];
|
||||
#endif
|
||||
});
|
||||
resolve(@true);
|
||||
} rejecter:^(NSString *code, NSString *message, NSError *error) {
|
||||
reject(code, message, error);
|
||||
}];
|
||||
} else {
|
||||
reject(@"执行报错", nil, nil);
|
||||
}
|
||||
}
|
||||
@@ -343,13 +342,14 @@ RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
|
||||
{
|
||||
@try {
|
||||
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);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update",
|
||||
"version": "10.28.11",
|
||||
"version": "10.29.6",
|
||||
"description": "react-native hot update",
|
||||
"main": "src/index",
|
||||
"scripts": {
|
||||
|
@@ -90,13 +90,6 @@ Pod::Spec.new do |s|
|
||||
|
||||
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.vendored_libraries = 'RCTPushy/libRCTPushy.a'
|
||||
s.pod_target_xcconfig = {
|
||||
@@ -112,22 +105,18 @@ Pod::Spec.new do |s|
|
||||
|
||||
# Conditionally add Expo dependency
|
||||
if valid_expo_project
|
||||
s.public_header_files = ['ios/ImportReact.h']
|
||||
s.dependency 'ExpoModulesCore'
|
||||
end
|
||||
|
||||
s.subspec 'RCTPushy' do |ss|
|
||||
ss.source_files = 'ios/RCTPushy/*.{h,m,mm,swift}'
|
||||
ss.public_header_files = ['ios/RCTPushy/*.h']
|
||||
end
|
||||
|
||||
s.subspec 'HDiffPatch' do |ss|
|
||||
ss.source_files = ['ios/RCTPushy/HDiffPatch/**/*.{h,m,c}',
|
||||
ss.source_files = ['ios/RCTPushy/**/*.{h,m,mm,c}',
|
||||
'android/jni/hpatch.{h,c}',
|
||||
'android/jni/HDiffPatch/libHDiffPatch/HPatch/*.{h,c}',
|
||||
'android/jni/HDiffPatch/file_for_patch.{h,c}',
|
||||
'android/jni/lzma/C/LzmaDec.{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
|
||||
|
||||
# Conditionally add Expo subspec and check ExpoModulesCore version
|
||||
|
132
src/client.ts
132
src/client.ts
@@ -1,33 +1,33 @@
|
||||
import { CheckResult, ClientOptions, ProgressData, EventType } from './type';
|
||||
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,
|
||||
emptyObj,
|
||||
enhancedFetch,
|
||||
joinUrls,
|
||||
log,
|
||||
noop,
|
||||
promiseAny,
|
||||
testUrls,
|
||||
} 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 = {
|
||||
// cn
|
||||
@@ -170,10 +170,12 @@ export class Pushy {
|
||||
getCheckUrl = (endpoint: string = this.options.server!.main) => {
|
||||
return `${endpoint}/checkUpdate/${this.options.appKey}`;
|
||||
};
|
||||
assertDebug = () => {
|
||||
assertDebug = (matter: string) => {
|
||||
if (__DEV__ && !this.options.debug) {
|
||||
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;
|
||||
}
|
||||
@@ -188,7 +190,7 @@ export class Pushy {
|
||||
this.report({ type: 'markSuccess' });
|
||||
};
|
||||
switchVersion = async (hash: string) => {
|
||||
if (!assertDev('switchVersion()')) {
|
||||
if (!this.assertDebug('switchVersion()')) {
|
||||
return;
|
||||
}
|
||||
if (assertHash(hash) && !sharedState.applyingUpdate) {
|
||||
@@ -199,7 +201,7 @@ export class Pushy {
|
||||
};
|
||||
|
||||
switchVersionLater = async (hash: string) => {
|
||||
if (!assertDev('switchVersionLater()')) {
|
||||
if (!this.assertDebug('switchVersionLater()')) {
|
||||
return;
|
||||
}
|
||||
if (assertHash(hash)) {
|
||||
@@ -208,7 +210,7 @@ export class Pushy {
|
||||
}
|
||||
};
|
||||
checkUpdate = async (extra?: Record<string, any>) => {
|
||||
if (!this.assertDebug()) {
|
||||
if (!this.assertDebug('checkUpdate()')) {
|
||||
return;
|
||||
}
|
||||
if (!assertWeb()) {
|
||||
@@ -261,7 +263,7 @@ export class Pushy {
|
||||
type: 'checking',
|
||||
message: this.options.appKey + ': ' + stringifyBody,
|
||||
});
|
||||
resp = await fetch(this.getCheckUrl(), fetchPayload);
|
||||
resp = await enhancedFetch(this.getCheckUrl(), fetchPayload);
|
||||
} catch (e: any) {
|
||||
this.report({
|
||||
type: 'errorChecking',
|
||||
@@ -272,7 +274,7 @@ export class Pushy {
|
||||
try {
|
||||
resp = await promiseAny(
|
||||
backupEndpoints.map(endpoint =>
|
||||
fetch(this.getCheckUrl(endpoint), fetchPayload),
|
||||
enhancedFetch(this.getCheckUrl(endpoint), fetchPayload),
|
||||
),
|
||||
);
|
||||
} catch (err: any) {
|
||||
@@ -393,7 +395,7 @@ export class Pushy {
|
||||
let lastError: any;
|
||||
let errorMessages: string[] = [];
|
||||
const diffUrl = await testUrls(joinUrls(paths, diff));
|
||||
if (diffUrl) {
|
||||
if (diffUrl && !__DEV__) {
|
||||
log('downloading diff');
|
||||
try {
|
||||
await PushyModule.downloadPatchFromPpk({
|
||||
@@ -406,60 +408,56 @@ export class Pushy {
|
||||
const errorMessage = `diff error: ${e.message}`;
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
if (__DEV__) {
|
||||
succeeded = 'diff';
|
||||
} else {
|
||||
log(errorMessage);
|
||||
}
|
||||
log(errorMessage);
|
||||
}
|
||||
}
|
||||
const pdiffUrl = await testUrls(joinUrls(paths, pdiff));
|
||||
if (!succeeded && pdiffUrl) {
|
||||
log('downloading pdiff');
|
||||
try {
|
||||
await PushyModule.downloadPatchFromPackage({
|
||||
updateUrl: pdiffUrl,
|
||||
hash,
|
||||
});
|
||||
succeeded = 'pdiff';
|
||||
} catch (e: any) {
|
||||
const errorMessage = `pdiff error: ${e.message}`;
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
if (__DEV__) {
|
||||
if (!succeeded) {
|
||||
const pdiffUrl = await testUrls(joinUrls(paths, pdiff));
|
||||
if (pdiffUrl && !__DEV__) {
|
||||
log('downloading pdiff');
|
||||
try {
|
||||
await PushyModule.downloadPatchFromPackage({
|
||||
updateUrl: pdiffUrl,
|
||||
hash,
|
||||
});
|
||||
succeeded = 'pdiff';
|
||||
} else {
|
||||
} catch (e: any) {
|
||||
const errorMessage = `pdiff error: ${e.message}`;
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
log(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
const fullUrl = await testUrls(joinUrls(paths, full));
|
||||
if (!succeeded && fullUrl) {
|
||||
log('downloading full patch');
|
||||
try {
|
||||
await PushyModule.downloadFullUpdate({
|
||||
updateUrl: fullUrl,
|
||||
hash,
|
||||
});
|
||||
succeeded = 'full';
|
||||
} catch (e: any) {
|
||||
const errorMessage = `full patch error: ${e.message}`;
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
if (__DEV__) {
|
||||
if (!succeeded) {
|
||||
const fullUrl = await testUrls(joinUrls(paths, full));
|
||||
if (fullUrl) {
|
||||
log('downloading full patch');
|
||||
try {
|
||||
await PushyModule.downloadFullUpdate({
|
||||
updateUrl: fullUrl,
|
||||
hash,
|
||||
});
|
||||
succeeded = 'full';
|
||||
} else {
|
||||
} catch (e: any) {
|
||||
const errorMessage = `full patch error: ${e.message}`;
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
log(errorMessage);
|
||||
}
|
||||
} else if (__DEV__) {
|
||||
log(
|
||||
`当前是开发环境,无法执行增量式热更新,重启不会生效。
|
||||
如果需要在开发环境中测试可生效的全量热更新(但也会在再次重启后重新连接 metro),
|
||||
请打开“忽略时间戳”开关再重试。`,
|
||||
);
|
||||
succeeded = 'full';
|
||||
}
|
||||
}
|
||||
if (sharedState.progressHandlers[hash]) {
|
||||
sharedState.progressHandlers[hash].remove();
|
||||
delete sharedState.progressHandlers[hash];
|
||||
}
|
||||
if (__DEV__) {
|
||||
return hash;
|
||||
}
|
||||
if (!succeeded) {
|
||||
this.report({
|
||||
type: 'errorUpdate',
|
||||
|
@@ -251,7 +251,7 @@ export const UpdateProvider = ({
|
||||
const markSuccess = client.markSuccess;
|
||||
|
||||
useEffect(() => {
|
||||
if (!client.assertDebug()) {
|
||||
if (!client.assertDebug('checkUpdate()')) {
|
||||
return;
|
||||
}
|
||||
const { checkStrategy, dismissErrorAfter, autoMarkSuccess } = options;
|
||||
|
31
src/utils.ts
31
src/utils.ts
@@ -40,13 +40,13 @@ const ping =
|
||||
: async (url: string) => {
|
||||
let pingFinished = false;
|
||||
return Promise.race([
|
||||
fetch(url, {
|
||||
enhancedFetch(url, {
|
||||
method: 'HEAD',
|
||||
})
|
||||
.then(({ status, statusText }) => {
|
||||
.then(({ status, statusText, url: finalUrl }) => {
|
||||
pingFinished = true;
|
||||
if (status === 200) {
|
||||
return url;
|
||||
return finalUrl;
|
||||
}
|
||||
log('ping failed', url, status, statusText);
|
||||
throw new Error('Ping failed');
|
||||
@@ -69,7 +69,7 @@ const ping =
|
||||
|
||||
export function joinUrls(paths: string[], fileName?: string) {
|
||||
if (fileName) {
|
||||
return paths.map(path => 'https://' + path + '/' + fileName);
|
||||
return paths.map(path => `https://${path}/${fileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,12 +99,19 @@ export const assertWeb = () => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const assertDev = (matter: string) => {
|
||||
if (__DEV__) {
|
||||
console.warn(
|
||||
`${matter} is not supported in development environment; no action taken.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// export const isAndroid70AndBelow = () => {
|
||||
// // android 7.0 and below devices do not support letsencrypt cert
|
||||
// // https://letsencrypt.org/2023/07/10/cross-sign-expiration/
|
||||
// return Platform.OS === 'android' && Platform.Version <= 24;
|
||||
// };
|
||||
|
||||
export const enhancedFetch = async (
|
||||
url: string,
|
||||
params: Parameters<typeof fetch>[1],
|
||||
) => {
|
||||
return fetch(url, params).catch(e => {
|
||||
log('fetch error', url, e);
|
||||
log('trying fallback to http');
|
||||
return fetch(url.replace('https', 'http'), params);
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user