1
0
mirror of https://gitcode.com/gh_mirrors/re/react-native-pushy.git synced 2025-09-18 00:16:10 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

Compare commits

..

59 Commits

Author SHA1 Message Date
sunnylqm
eea7ff26f2 v5.10.0 2020-12-18 11:17:07 +08:00
sunnylqm
684dc8267d Back compatibility 2020-12-18 11:16:49 +08:00
sunnylqm
5786bf8132 v5.10.0-beta0 2020-12-17 00:15:48 +08:00
sunnylqm
1bd5fbbc94 Refactor ios rollback 2020-12-17 00:12:30 +08:00
sunnylqm
cd2eb9417a Update gitignore 2020-11-03 16:17:24 +08:00
sunnylqm
7d8730f590 v5.9.3 2020-11-03 16:17:03 +08:00
sunnylqm
e3081a02db Rename file_paths.xml to avoid overwrite 2020-11-03 15:52:59 +08:00
sunnylqm
ec8c475c54 Add webview test 2020-10-21 15:51:51 +08:00
sunnylqm
ac18785e50 Add webview 2020-10-21 08:26:55 +08:00
sunnylqm
e80317415c Upgrade 0.63.3 2020-10-21 08:12:52 +08:00
sunnylqm
f5c307deca v5.9.1 2020-10-06 23:41:08 +08:00
sunnylqm
b4feae292d Fix index.d.ts 2020-10-06 23:40:51 +08:00
sunnylqm
a1c2679427 v5.9.0 2020-09-27 22:32:30 +08:00
sunnylqm
17ff366f51 Implement download and install apk 2020-09-27 22:16:27 +08:00
sunnylqm
3c5792423e v5.8.3 2020-09-24 22:45:12 +08:00
sunnylqm
d071fbfc2b Fix ios bridge reload 2020-09-24 22:44:50 +08:00
sunnylqm
17dffa1eb5 Rename hashname -> hash 2020-09-24 22:44:37 +08:00
sunnylqm
bcd61315e9 v5.8.2 2020-09-24 19:36:09 +08:00
sunnylqm
f626cc1933 Fix download event and remove unzip event 2020-09-24 19:31:27 +08:00
sunnylqm
4ba3f25972 v5.8.1 2020-09-17 23:20:32 +08:00
sunnylqm
cd695b1ffb Revert rctreloadcommand 2020-09-17 23:18:17 +08:00
sunnylqm
37a1a5a18b Merge branch 'master' of github.com:reactnativecn/react-native-pushy
# Conflicts:
#	package.json
2020-09-16 17:35:16 +08:00
sunnylqm
5a2ebf8df7 Fix example setState 2020-09-16 14:42:45 +08:00
sunnylqm
95ba5f364b v5.8.0 2020-09-16 14:37:32 +08:00
sunnylqm
841228c341 Fix example 2020-09-16 14:36:37 +08:00
sunnylqm
93049f1e54 v5.8.0-beta1 2020-09-16 13:02:53 +08:00
sunnylqm
a966655faf Implement download progress 2020-09-16 13:01:14 +08:00
sunnylqm
a4052091e0 Update example to 0.63 2020-09-01 15:29:13 +08:00
sunnylqm
ebb5defb10 v5.7.2 2020-09-01 10:51:43 +08:00
sunnylqm
a509ff8e30 Cleanup 2020-09-01 10:51:15 +08:00
sunnylqm
59fcba15ee Implement blockupdate on android 2020-08-31 18:39:03 +08:00
sunnylqm
c6f9bb20a1 Add client info and uuid 2020-08-31 11:47:08 +08:00
sunnylqm
9e6c7ea769 setBlockUpdate 2020-08-31 01:17:28 +08:00
sunnylqm
f461c8ddd2 Update endpoint and example 2020-08-26 00:44:34 +08:00
sunnylqm
4cbeb7bec4 v5.7.0 2020-08-13 00:32:52 +08:00
sunnylqm
ed7f5ac606 Detect android bundle url 2020-08-13 00:32:07 +08:00
sunnylqm
6abb2c7a5d Unify download progress event 2020-08-09 00:08:30 +08:00
sunnylqm
a4a372f17e Revert "Exclude backup"
This reverts commit 2d805fb38e.
2020-08-08 21:09:15 +08:00
sunnylqm
48693e3b45 v5.7.0-beta1 2020-08-04 13:05:14 +08:00
sunnylqm
2d805fb38e Exclude backup 2020-08-04 13:03:53 +08:00
sunnylqm
92c421b30f Fix typo 2020-08-04 13:03:37 +08:00
sunnylqm
dbd0880295 Fix custom endpoints 2020-07-28 23:34:06 +08:00
sunnylqm
f110df1206 Add custom endpoints 2020-07-28 23:15:42 +08:00
sunnylqm
d17eac48f0 v5.6.0 2020-05-26 23:29:14 +08:00
sunnylqm
8e1a639dda Merge branch 'fix-app-json' 2020-05-25 15:00:21 +08:00
sunnylqm
5999670917 Redirect doc 2020-05-24 17:17:07 +08:00
sunnylqm
0f6875d8d5 v5.6.0-beta.1 2020-05-23 00:34:47 +08:00
sunnylqm
3752ad4e5d Try to fix app.json issue 2020-05-23 00:17:30 +08:00
Sunny Luo
a2f01b6213 Update README.md 2020-05-21 22:21:27 +08:00
Sunny Luo
c2499f799b Update README.md 2020-05-21 22:21:10 +08:00
sunnylqm
680f77a8d8 v5.5.10 2020-04-30 18:09:05 +08:00
sunnylqm
eaae1286f4 Add link error hint 2020-04-30 17:59:28 +08:00
sunnylqm
20a21ae894 v5.5.9 2020-04-14 22:59:19 +08:00
sunnylqm
5abe7b181b Fix ios script path 2020-04-14 22:58:53 +08:00
Sunny Luo
e859238d97 Update changelog.md 2020-04-07 16:38:06 +08:00
sunnylqm
7796090e72 v5.5.8 2020-04-02 12:09:38 +08:00
sunnylqm
f07be8cf0b Merge branch 'customInstanceManager' 2020-04-02 12:09:13 +08:00
Sunny Luo
4a84622c04 Update domains.json 2020-04-02 00:44:18 +08:00
Sunny Luo
cf812eacda Update domains.json 2020-04-02 00:43:21 +08:00
56 changed files with 3628 additions and 5890 deletions

10
.gitignore vendored
View File

@@ -1,7 +1,6 @@
/.idea .vscode
/node_modules android/build
/android/build android/obj
/android/obj
*.iml *.iml
# OSX # OSX
@@ -42,4 +41,5 @@ local.properties
node_modules/ node_modules/
npm-debug.log npm-debug.log
Example/**/update.json Example/**/update.json
yarn-error.log

View File

@@ -1,11 +1,11 @@
/.idea .babelrc
/.babelrc .npmignore
/.npmignore .eslintrc
/.eslintrc .nvmrc
/.nvmrc .travis.yml
/.travis.yml Example
/Example android/build
/android/build .vscode
# OSX # OSX
# #
@@ -45,4 +45,5 @@ Example
yarn.lock yarn.lock
android/jni android/jni
domains.json domains.json
endpoints.json

View File

@@ -1,75 +0,0 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.105.0

View File

@@ -15,10 +15,12 @@ import com.android.build.OutputFile
* // the name of the generated asset file containing your JS bundle * // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle", * bundleAssetName: "index.android.bundle",
* *
* // the entry file for bundle generation * // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js", * entryFile: "index.android.js",
* *
* // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format * // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle", * bundleCommand: "ram-bundle",
* *
* // whether to bundle JS and assets in debug mode * // whether to bundle JS and assets in debug mode
@@ -76,7 +78,6 @@ import com.android.build.OutputFile
*/ */
project.ext.react = [ project.ext.react = [
entryFile: "index.js",
enableHermes: false, // clean and rebuild if changing enableHermes: false, // clean and rebuild if changing
] ]
@@ -155,13 +156,15 @@ android {
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
release { release {
crunchPngs false
// Caution! In production, you need to generate your own keystore file. // Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android. // see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
} }
} }
// applicationVariants are e.g. debug, release // applicationVariants are e.g. debug, release
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
@@ -180,8 +183,24 @@ android {
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) { if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/"; def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar") debugImplementation files(hermesPath + "hermes-debug.aar")
@@ -198,4 +217,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
into 'libs' into 'libs'
} }
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.testhotupdate;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

View File

@@ -14,7 +14,8 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -4,6 +4,7 @@ import android.app.Application;
import android.content.Context; import android.content.Context;
import com.facebook.react.PackageList; import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
@@ -50,23 +51,28 @@ public class MainApplication extends Application implements ReactApplication {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
SoLoader.init(this, /* native exopackage */ false); SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this); // Remove this line if you don't want Flipper enabled initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
} }
/** /**
* Loads Flipper in React Native templates. * Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
* *
* @param context * @param context
* @param reactInstanceManager
*/ */
private static void initializeFlipper(Context context) { private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
try { try {
/* /*
We use reflection here to pick up the class that initializes Flipper, We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode since Flipper library is not available in release mode
*/ */
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper"); Class<?> aClass = Class.forName("com.testhotupdate.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context); aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {

View File

@@ -2,17 +2,17 @@
buildscript { buildscript {
ext { ext {
buildToolsVersion = "28.0.3" buildToolsVersion = "29.0.2"
minSdkVersion = 16 minSdkVersion = 21
compileSdkVersion = 28 compileSdkVersion = 29
targetSdkVersion = 28 targetSdkVersion = 29
} }
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath('com.android.tools.build:gradle:3.5.1') classpath('com.android.tools.build:gradle:3.5.3')
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
@@ -33,6 +33,6 @@ allprojects {
google() google()
jcenter() jcenter()
maven { url 'https://jitpack.io' } maven { url 'https://www.jitpack.io' }
} }
} }

View File

@@ -17,5 +17,12 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.54.0

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -7,7 +7,7 @@
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # https://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
@@ -125,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -154,19 +154,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong exec "$JAVACMD" "$@"
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@@ -5,7 +5,7 @@
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem http://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -97,4 +100,4 @@ exit /b 1
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

View File

@@ -1,39 +1,20 @@
platform :ios, '9.0' require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '10.0'
target 'testHotUpdate' do target 'testHotUpdate' do
# Pods for testHotUpdate config = use_native_modules!
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/'
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' use_react_native!(:path => config["reactNativePath"])
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' # Enables Flipper.
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' #
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' # Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable these next few lines.
use_native_modules! use_flipper!('Flipper' => '0.54.0')
post_install do |installer|
flipper_post_install(installer)
end
end end

View File

@@ -1,245 +1,348 @@
PODS: PODS:
- boost-for-react-native (1.63.0) - boost-for-react-native (1.63.0)
- CocoaAsyncSocket (7.6.4)
- CocoaLibEvent (1.0.0)
- DoubleConversion (1.1.6) - DoubleConversion (1.1.6)
- FBLazyVector (0.61.4) - FBLazyVector (0.63.3)
- FBReactNativeSpec (0.61.4): - FBReactNativeSpec (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- RCTRequired (= 0.61.4) - RCTRequired (= 0.63.3)
- RCTTypeSafety (= 0.61.4) - RCTTypeSafety (= 0.63.3)
- React-Core (= 0.61.4) - React-Core (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.61.4) - ReactCommon/turbomodule/core (= 0.63.3)
- Folly (2018.10.22.00): - Flipper (0.54.0):
- Flipper-Folly (~> 2.2)
- Flipper-RSocket (~> 1.1)
- Flipper-DoubleConversion (1.1.7)
- Flipper-Folly (2.2.0):
- boost-for-react-native
- CocoaLibEvent (~> 1.0)
- Flipper-DoubleConversion
- Flipper-Glog
- OpenSSL-Universal (= 1.0.2.19)
- Flipper-Glog (0.3.6)
- Flipper-PeerTalk (0.0.4)
- Flipper-RSocket (1.1.0):
- Flipper-Folly (~> 2.2)
- FlipperKit (0.54.0):
- FlipperKit/Core (= 0.54.0)
- FlipperKit/Core (0.54.0):
- Flipper (~> 0.54.0)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- FlipperKit/CppBridge (0.54.0):
- Flipper (~> 0.54.0)
- FlipperKit/FBCxxFollyDynamicConvert (0.54.0):
- Flipper-Folly (~> 2.2)
- FlipperKit/FBDefines (0.54.0)
- FlipperKit/FKPortForwarding (0.54.0):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- FlipperKit/FlipperKitHighlightOverlay (0.54.0)
- FlipperKit/FlipperKitLayoutPlugin (0.54.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- YogaKit (~> 1.18)
- FlipperKit/FlipperKitLayoutTextSearchable (0.54.0)
- FlipperKit/FlipperKitNetworkPlugin (0.54.0):
- FlipperKit/Core
- FlipperKit/FlipperKitReactPlugin (0.54.0):
- FlipperKit/Core
- FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0):
- FlipperKit/Core
- FlipperKit/SKIOSNetworkPlugin (0.54.0):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- Folly (2020.01.13.00):
- boost-for-react-native - boost-for-react-native
- DoubleConversion - DoubleConversion
- Folly/Default (= 2018.10.22.00) - Folly/Default (= 2020.01.13.00)
- glog - glog
- Folly/Default (2018.10.22.00): - Folly/Default (2020.01.13.00):
- boost-for-react-native - boost-for-react-native
- DoubleConversion - DoubleConversion
- glog - glog
- glog (0.3.5) - glog (0.3.5)
- RCTRequired (0.61.4) - OpenSSL-Universal (1.0.2.19):
- RCTTypeSafety (0.61.4): - OpenSSL-Universal/Static (= 1.0.2.19)
- FBLazyVector (= 0.61.4) - OpenSSL-Universal/Static (1.0.2.19)
- Folly (= 2018.10.22.00) - RCTRequired (0.63.3)
- RCTRequired (= 0.61.4) - RCTTypeSafety (0.63.3):
- React-Core (= 0.61.4) - FBLazyVector (= 0.63.3)
- React (0.61.4): - Folly (= 2020.01.13.00)
- React-Core (= 0.61.4) - RCTRequired (= 0.63.3)
- React-Core/DevSupport (= 0.61.4) - React-Core (= 0.63.3)
- React-Core/RCTWebSocket (= 0.61.4) - React (0.63.3):
- React-RCTActionSheet (= 0.61.4) - React-Core (= 0.63.3)
- React-RCTAnimation (= 0.61.4) - React-Core/DevSupport (= 0.63.3)
- React-RCTBlob (= 0.61.4) - React-Core/RCTWebSocket (= 0.63.3)
- React-RCTImage (= 0.61.4) - React-RCTActionSheet (= 0.63.3)
- React-RCTLinking (= 0.61.4) - React-RCTAnimation (= 0.63.3)
- React-RCTNetwork (= 0.61.4) - React-RCTBlob (= 0.63.3)
- React-RCTSettings (= 0.61.4) - React-RCTImage (= 0.63.3)
- React-RCTText (= 0.61.4) - React-RCTLinking (= 0.63.3)
- React-RCTVibration (= 0.61.4) - React-RCTNetwork (= 0.63.3)
- React-Core (0.61.4): - React-RCTSettings (= 0.63.3)
- Folly (= 2018.10.22.00) - React-RCTText (= 0.63.3)
- React-RCTVibration (= 0.63.3)
- React-callinvoker (0.63.3)
- React-Core (0.63.3):
- Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default (= 0.61.4) - React-Core/Default (= 0.63.3)
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/CoreModulesHeaders (0.61.4): - React-Core/CoreModulesHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/Default (0.61.4): - React-Core/Default (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/DevSupport (0.61.4): - React-Core/DevSupport (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default (= 0.61.4) - React-Core/Default (= 0.63.3)
- React-Core/RCTWebSocket (= 0.61.4) - React-Core/RCTWebSocket (= 0.63.3)
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- React-jsinspector (= 0.61.4) - React-jsinspector (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTActionSheetHeaders (0.61.4): - React-Core/RCTActionSheetHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTAnimationHeaders (0.61.4): - React-Core/RCTAnimationHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTBlobHeaders (0.61.4): - React-Core/RCTBlobHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTImageHeaders (0.61.4): - React-Core/RCTImageHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTLinkingHeaders (0.61.4): - React-Core/RCTLinkingHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTNetworkHeaders (0.61.4): - React-Core/RCTNetworkHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTSettingsHeaders (0.61.4): - React-Core/RCTSettingsHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTTextHeaders (0.61.4): - React-Core/RCTTextHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTVibrationHeaders (0.61.4): - React-Core/RCTVibrationHeaders (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-Core/RCTWebSocket (0.61.4): - React-Core/RCTWebSocket (0.63.3):
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-Core/Default (= 0.61.4) - React-Core/Default (= 0.63.3)
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsiexecutor (= 0.61.4) - React-jsiexecutor (= 0.63.3)
- Yoga - Yoga
- React-CoreModules (0.61.4): - React-CoreModules (0.63.3):
- FBReactNativeSpec (= 0.61.4) - FBReactNativeSpec (= 0.63.3)
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.61.4) - RCTTypeSafety (= 0.63.3)
- React-Core/CoreModulesHeaders (= 0.61.4) - React-Core/CoreModulesHeaders (= 0.63.3)
- React-RCTImage (= 0.61.4) - React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.61.4) - React-RCTImage (= 0.63.3)
- React-cxxreact (0.61.4): - ReactCommon/turbomodule/core (= 0.63.3)
- React-cxxreact (0.63.3):
- boost-for-react-native (= 1.63.0) - boost-for-react-native (= 1.63.0)
- DoubleConversion - DoubleConversion
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-jsinspector (= 0.61.4) - React-callinvoker (= 0.63.3)
- React-jsi (0.61.4): - React-jsinspector (= 0.63.3)
- React-jsi (0.63.3):
- boost-for-react-native (= 1.63.0) - boost-for-react-native (= 1.63.0)
- DoubleConversion - DoubleConversion
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-jsi/Default (= 0.61.4) - React-jsi/Default (= 0.63.3)
- React-jsi/Default (0.61.4): - React-jsi/Default (0.63.3):
- boost-for-react-native (= 1.63.0) - boost-for-react-native (= 1.63.0)
- DoubleConversion - DoubleConversion
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-jsiexecutor (0.61.4): - React-jsiexecutor (0.63.3):
- DoubleConversion - DoubleConversion
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-cxxreact (= 0.61.4) - React-cxxreact (= 0.63.3)
- React-jsi (= 0.61.4) - React-jsi (= 0.63.3)
- React-jsinspector (0.61.4) - React-jsinspector (0.63.3)
- react-native-update (5.5.0): - react-native-update (5.9.1):
- React - React
- react-native-update/BSDiff (= 5.5.0) - react-native-update/BSDiff (= 5.9.1)
- react-native-update/RCTPushy (= 5.5.0) - react-native-update/RCTPushy (= 5.9.1)
- SSZipArchive - SSZipArchive
- react-native-update/BSDiff (5.5.0): - react-native-update/BSDiff (5.9.1):
- React - React
- SSZipArchive - SSZipArchive
- react-native-update/RCTPushy (5.5.0): - react-native-update/RCTPushy (5.9.1):
- React - React
- SSZipArchive - SSZipArchive
- React-RCTActionSheet (0.61.4): - react-native-webview (10.9.2):
- React-Core/RCTActionSheetHeaders (= 0.61.4) - React-Core
- React-RCTAnimation (0.61.4): - React-RCTActionSheet (0.63.3):
- React-Core/RCTAnimationHeaders (= 0.61.4) - React-Core/RCTActionSheetHeaders (= 0.63.3)
- React-RCTBlob (0.61.4): - React-RCTAnimation (0.63.3):
- React-Core/RCTBlobHeaders (= 0.61.4) - FBReactNativeSpec (= 0.63.3)
- React-Core/RCTWebSocket (= 0.61.4) - Folly (= 2020.01.13.00)
- React-jsi (= 0.61.4) - RCTTypeSafety (= 0.63.3)
- React-RCTNetwork (= 0.61.4) - React-Core/RCTAnimationHeaders (= 0.63.3)
- React-RCTImage (0.61.4): - React-jsi (= 0.63.3)
- React-Core/RCTImageHeaders (= 0.61.4) - ReactCommon/turbomodule/core (= 0.63.3)
- React-RCTNetwork (= 0.61.4) - React-RCTBlob (0.63.3):
- React-RCTLinking (0.61.4): - FBReactNativeSpec (= 0.63.3)
- React-Core/RCTLinkingHeaders (= 0.61.4) - Folly (= 2020.01.13.00)
- React-RCTNetwork (0.61.4): - React-Core/RCTBlobHeaders (= 0.63.3)
- React-Core/RCTNetworkHeaders (= 0.61.4) - React-Core/RCTWebSocket (= 0.63.3)
- React-RCTSettings (0.61.4): - React-jsi (= 0.63.3)
- React-Core/RCTSettingsHeaders (= 0.61.4) - React-RCTNetwork (= 0.63.3)
- React-RCTText (0.61.4): - ReactCommon/turbomodule/core (= 0.63.3)
- React-Core/RCTTextHeaders (= 0.61.4) - React-RCTImage (0.63.3):
- React-RCTVibration (0.61.4): - FBReactNativeSpec (= 0.63.3)
- React-Core/RCTVibrationHeaders (= 0.61.4) - Folly (= 2020.01.13.00)
- ReactCommon/jscallinvoker (0.61.4): - RCTTypeSafety (= 0.63.3)
- React-Core/RCTImageHeaders (= 0.63.3)
- React-jsi (= 0.63.3)
- React-RCTNetwork (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.63.3)
- React-RCTLinking (0.63.3):
- FBReactNativeSpec (= 0.63.3)
- React-Core/RCTLinkingHeaders (= 0.63.3)
- React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.63.3)
- React-RCTNetwork (0.63.3):
- FBReactNativeSpec (= 0.63.3)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.3)
- React-Core/RCTNetworkHeaders (= 0.63.3)
- React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.63.3)
- React-RCTSettings (0.63.3):
- FBReactNativeSpec (= 0.63.3)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.3)
- React-Core/RCTSettingsHeaders (= 0.63.3)
- React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.63.3)
- React-RCTText (0.63.3):
- React-Core/RCTTextHeaders (= 0.63.3)
- React-RCTVibration (0.63.3):
- FBReactNativeSpec (= 0.63.3)
- Folly (= 2020.01.13.00)
- React-Core/RCTVibrationHeaders (= 0.63.3)
- React-jsi (= 0.63.3)
- ReactCommon/turbomodule/core (= 0.63.3)
- ReactCommon/turbomodule/core (0.63.3):
- DoubleConversion - DoubleConversion
- Folly (= 2018.10.22.00) - Folly (= 2020.01.13.00)
- glog - glog
- React-cxxreact (= 0.61.4) - React-callinvoker (= 0.63.3)
- ReactCommon/turbomodule/core (0.61.4): - React-Core (= 0.63.3)
- DoubleConversion - React-cxxreact (= 0.63.3)
- Folly (= 2018.10.22.00) - React-jsi (= 0.63.3)
- glog - SSZipArchive (2.2.3)
- React-Core (= 0.61.4)
- React-cxxreact (= 0.61.4)
- React-jsi (= 0.61.4)
- ReactCommon/jscallinvoker (= 0.61.4)
- SSZipArchive (2.2.2)
- Yoga (1.14.0) - Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
DEPENDENCIES: DEPENDENCIES:
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
- Flipper (= 0.54.0)
- Flipper-DoubleConversion (= 1.1.7)
- Flipper-Folly (~> 2.2)
- Flipper-Glog (= 0.3.6)
- Flipper-PeerTalk (~> 0.0.4)
- Flipper-RSocket (~> 1.1)
- FlipperKit (= 0.54.0)
- FlipperKit/Core (= 0.54.0)
- FlipperKit/CppBridge (= 0.54.0)
- FlipperKit/FBCxxFollyDynamicConvert (= 0.54.0)
- FlipperKit/FBDefines (= 0.54.0)
- FlipperKit/FKPortForwarding (= 0.54.0)
- FlipperKit/FlipperKitHighlightOverlay (= 0.54.0)
- FlipperKit/FlipperKitLayoutPlugin (= 0.54.0)
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.54.0)
- FlipperKit/FlipperKitNetworkPlugin (= 0.54.0)
- FlipperKit/FlipperKitReactPlugin (= 0.54.0)
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.54.0)
- FlipperKit/SKIOSNetworkPlugin (= 0.54.0)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`) - React (from `../node_modules/react-native/`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Core (from `../node_modules/react-native/`) - React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`)
@@ -249,6 +352,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-update (from `../../..`) - react-native-update (from `../../..`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
@@ -258,14 +362,24 @@ DEPENDENCIES:
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- boost-for-react-native - boost-for-react-native
- CocoaAsyncSocket
- CocoaLibEvent
- Flipper
- Flipper-DoubleConversion
- Flipper-Folly
- Flipper-Glog
- Flipper-PeerTalk
- Flipper-RSocket
- FlipperKit
- OpenSSL-Universal
- SSZipArchive - SSZipArchive
- YogaKit
EXTERNAL SOURCES: EXTERNAL SOURCES:
DoubleConversion: DoubleConversion:
@@ -284,6 +398,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/TypeSafety" :path: "../node_modules/react-native/Libraries/TypeSafety"
React: React:
:path: "../node_modules/react-native/" :path: "../node_modules/react-native/"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Core: React-Core:
:path: "../node_modules/react-native/" :path: "../node_modules/react-native/"
React-CoreModules: React-CoreModules:
@@ -298,6 +414,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector" :path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-update: react-native-update:
:path: "../../.." :path: "../../.."
react-native-webview:
:path: "../node_modules/react-native-webview"
React-RCTActionSheet: React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS" :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation: React-RCTAnimation:
@@ -323,34 +441,47 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
FBLazyVector: feb35a6b7f7b50f367be07f34012f34a79282fa3 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
FBReactNativeSpec: 51477b84b1bf7ab6f9ef307c24e3dd675391be44 DoubleConversion: cde416483dac037923206447da6e1454df403714
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d
glog: 1f3da668190260b06b429bb211bfbee5cd790c28 FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f
RCTRequired: f3b3fb6f4723e8e52facb229d0c75fdc76773849 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
RCTTypeSafety: 2ec60de6abb1db050b56ecc4b60188026078fd10 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
React: 10e0130b57e55a7cd8c3dee37c1261102ce295f4 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
React-Core: 636212410772d05f3a1eb79d965df2962ca1c70b Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
React-CoreModules: 6f70d5e41919289c582f88c9ad9923fe5c87400a Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
React-cxxreact: ddecbe9157ec1743f52ea17bf8d95debc0d6e846 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
React-jsi: ca921f4041505f9d5197139b2d09eeb020bb12e8 FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
React-jsiexecutor: 8dfb73b987afa9324e4009bdce62a18ce23d983c Folly: b73c3869541e86821df3c387eb0af5f65addfab4
React-jsinspector: d15478d0a8ada19864aa4d1cc1c697b41b3fa92f glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
react-native-update: 0696134a23c2ad1be899c12b33f9d3521284d458 OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
React-RCTActionSheet: 7369b7c85f99b6299491333affd9f01f5a130c22 RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047
React-RCTAnimation: d07be15b2bd1d06d89417eb0343f98ffd2b099a7 RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab
React-RCTBlob: 8e0b23d95c9baa98f6b0e127e07666aaafd96c34 React: f36e90f3ceb976546e97df3403e37d226f79d0e3
React-RCTImage: 443050d14a66e8c2332e9c055f45689d23e15cc7 React-callinvoker: 18874f621eb96625df7a24a7dc8d6e07391affcd
React-RCTLinking: ce9a90ba155aec41be49e75ec721bbae2d48a47e React-Core: ac3d816b8e3493970153f4aaf0cff18af0bb95e6
React-RCTNetwork: 41fe54bacc67dd00e6e4c4d30dd98a13e4beabc8 React-CoreModules: 4016d3a4e518bcfc4f5a51252b5a05692ca6f0e1
React-RCTSettings: 45e3e0a6470310b2dab2ccc6d1d73121ba3ea936 React-cxxreact: ffc9129013b87cb36cf3f30a86695a3c397b0f99
React-RCTText: 21934e0a51d522abcd0a275407e80af45d6fd9ec React-jsi: df07aa95b39c5be3e41199921509bfa929ed2b9d
React-RCTVibration: 0f76400ee3cec6edb9c125da49fed279340d145a React-jsiexecutor: b56c03e61c0dd5f5801255f2160a815f4a53d451
ReactCommon: a6a294e7028ed67b926d29551aa9394fd989c24c React-jsinspector: 8e68ffbfe23880d3ee9bafa8be2777f60b25cbe2
SSZipArchive: fa16b8cc4cdeceb698e5e5d9f67e9558532fbf23 react-native-update: 74ae0ad726a7cd5194b377361b7a3e921a65201c
Yoga: ba3d99dbee6c15ea6bbe3783d1f0cb1ffb79af0f react-native-webview: 4e96d493f9f90ba4f03b28933f30b2964df07e39
React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa
React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2
React-RCTBlob: 0b284339cbe4b15705a05e2313a51c6d8b51fa40
React-RCTImage: d1756599ebd4dc2cb19d1682fe67c6b976658387
React-RCTLinking: 9af0a51c6d6a4dd1674daadafffc6d03033a6d18
React-RCTNetwork: 332c83929cc5eae0b3bbca4add1d668e1fc18bda
React-RCTSettings: d6953772cfd55f2c68ad72b7ef29efc7ec49f773
React-RCTText: 65a6de06a7389098ce24340d1d3556015c38f746
React-RCTVibration: 8e9fb25724a0805107fc1acc9075e26f814df454
ReactCommon: 4167844018c9ed375cc01a843e9ee564399e53c3
SSZipArchive: 62d4947b08730e4cda640473b0066d209ff033c9
Yoga: 7d13633d129fd179e01b8953d38d47be90db185a
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 244ba888c650d3945bf72a8d01516fb0f1b3b097 PODFILE CHECKSUM: 449e295f5242b426c8459fd24a8812cc985916d0
COCOAPODS: 1.8.4 COCOAPODS: 1.9.3

View File

@@ -0,0 +1,9 @@
//
// dummy.swift
// testHotUpdate
//
// Created by Qingming, Sunny Luo on 9/1/20.
// Copyright © 2020 Facebook. All rights reserved.
//
import Foundation

View File

@@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

View File

@@ -12,6 +12,7 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
7610A16EF1CB8A7644EAFA55 /* libPods-testHotUpdate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 28C264AEBE1E206870F9D871 /* libPods-testHotUpdate.a */; }; 7610A16EF1CB8A7644EAFA55 /* libPods-testHotUpdate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 28C264AEBE1E206870F9D871 /* libPods-testHotUpdate.a */; };
F1CBCFD724FE1CF80019170D /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1CBCFD624FE1CF80019170D /* dummy.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -37,6 +38,8 @@
ED1DB2CEADC1A82A43867C0E /* Pods-testHotUpdateTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testHotUpdateTests.release.xcconfig"; path = "Target Support Files/Pods-testHotUpdateTests/Pods-testHotUpdateTests.release.xcconfig"; sourceTree = "<group>"; }; ED1DB2CEADC1A82A43867C0E /* Pods-testHotUpdateTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testHotUpdateTests.release.xcconfig"; path = "Target Support Files/Pods-testHotUpdateTests/Pods-testHotUpdateTests.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
F1CBCFD524FE1CF80019170D /* testHotUpdate-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "testHotUpdate-Bridging-Header.h"; sourceTree = "<group>"; };
F1CBCFD624FE1CF80019170D /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dummy.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -76,6 +79,8 @@
13B07FB61A68108700A75B9A /* Info.plist */, 13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */, 13B07FB71A68108700A75B9A /* main.m */,
F1CBCFD624FE1CF80019170D /* dummy.swift */,
F1CBCFD524FE1CF80019170D /* testHotUpdate-Bridging-Header.h */,
); );
name = testHotUpdate; name = testHotUpdate;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -154,6 +159,12 @@
attributes = { attributes = {
LastUpgradeCheck = 0940; LastUpgradeCheck = 0940;
ORGANIZATIONNAME = Facebook; ORGANIZATIONNAME = Facebook;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = JD75Q9JJL2;
LastSwiftMigration = 1160;
};
};
}; };
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testHotUpdate" */; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testHotUpdate" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
@@ -199,7 +210,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
}; };
1CD78CE8A2E7B88FAE48FCEE /* [CP] Copy Pods Resources */ = { 1CD78CE8A2E7B88FAE48FCEE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
@@ -208,10 +219,12 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testHotUpdate/Pods-testHotUpdate-resources.sh", "${PODS_ROOT}/Target Support Files/Pods-testHotUpdate/Pods-testHotUpdate-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
"${PODS_ROOT}/../../../../ios/pushy_build_time.txt", "${PODS_ROOT}/../../../../ios/pushy_build_time.txt",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pushy_build_time.txt", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pushy_build_time.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -268,6 +281,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
F1CBCFD724FE1CF80019170D /* dummy.swift in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -292,8 +306,10 @@
baseConfigurationReference = 84EBA9C1A760F4136B306391 /* Pods-testHotUpdate.debug.xcconfig */; baseConfigurationReference = 84EBA9C1A760F4136B306391 /* Pods-testHotUpdate.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO; DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = JD75Q9JJL2;
INFOPLIST_FILE = testHotUpdate/Info.plist; INFOPLIST_FILE = testHotUpdate/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@@ -303,6 +319,9 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = testHotUpdate; PRODUCT_NAME = testHotUpdate;
SWIFT_OBJC_BRIDGING_HEADER = "testHotUpdate-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Debug; name = Debug;
@@ -312,7 +331,9 @@
baseConfigurationReference = 1A3E77317B15A5C3816ACE3A /* Pods-testHotUpdate.release.xcconfig */; baseConfigurationReference = 1A3E77317B15A5C3816ACE3A /* Pods-testHotUpdate.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = JD75Q9JJL2;
INFOPLIST_FILE = testHotUpdate/Info.plist; INFOPLIST_FILE = testHotUpdate/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@@ -322,6 +343,8 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = testHotUpdate; PRODUCT_NAME = testHotUpdate;
SWIFT_OBJC_BRIDGING_HEADER = "testHotUpdate-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Release; name = Release;

View File

@@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testHotUpdate.app"
BlueprintName = "testHotUpdate"
ReferencedContainer = "container:testHotUpdate.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
@@ -67,17 +76,6 @@
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testHotUpdate.app"
BlueprintName = "testHotUpdate"
ReferencedContainer = "container:testHotUpdate.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@@ -99,8 +97,6 @@
ReferencedContainer = "container:testHotUpdate.xcodeproj"> ReferencedContainer = "container:testHotUpdate.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@@ -12,10 +12,32 @@
#import <React/RCTRootView.h> #import <React/RCTRootView.h>
#import "RCTPushy.h" #import "RCTPushy.h"
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
@implementation AppDelegate @implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ {
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"testHotUpdate" moduleName:@"testHotUpdate"

View File

@@ -7,22 +7,24 @@
"ios": "react-native run-ios", "ios": "react-native run-ios",
"start": "react-native start", "start": "react-native start",
"test": "jest", "test": "jest",
"lint": "eslint ." "lint": "eslint .",
"apk": "(cd android && ./gradlew aR)"
}, },
"dependencies": { "dependencies": {
"react": "16.9.0", "react": "16.13.1",
"react-native": "0.61.4", "react-native": "0.63.3",
"react-native-update": "link:../.." "react-native-update": "link:../..",
"react-native-webview": "^10.9.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.6.2", "@babel/core": "^7.8.4",
"@babel/runtime": "^7.6.2", "@babel/runtime": "^7.8.4",
"@react-native-community/eslint-config": "^0.0.5", "@react-native-community/eslint-config": "^1.1.0",
"babel-jest": "^24.9.0", "babel-jest": "^25.1.0",
"eslint": "^6.5.1", "eslint": "^6.5.1",
"jest": "^24.9.0", "jest": "^25.1.0",
"metro-react-native-babel-preset": "^0.56.0", "metro-react-native-babel-preset": "^0.59.0",
"react-test-renderer": "16.9.0" "react-test-renderer": "16.13.1"
}, },
"jest": { "jest": {
"preset": "react-native" "preset": "react-native"

View File

@@ -20,12 +20,17 @@ import {
switchVersion, switchVersion,
switchVersionLater, switchVersionLater,
markSuccess, markSuccess,
downloadAndInstallApk,
} from 'react-native-update'; } from 'react-native-update';
import _updateConfig from '../update.json'; import _updateConfig from '../update.json';
const {appKey} = _updateConfig[Platform.OS]; const {appKey} = _updateConfig[Platform.OS];
export default class App extends Component { export default class App extends Component {
state = {
received: 0,
total: 0,
};
componentDidMount() { componentDidMount() {
if (isRolledBack) { if (isRolledBack) {
Alert.alert('提示', '刚刚更新失败了,版本被回滚.'); Alert.alert('提示', '刚刚更新失败了,版本被回滚.');
@@ -50,23 +55,34 @@ export default class App extends Component {
); );
} }
} }
doUpdate = async info => { doUpdate = async (info) => {
const hash = await downloadUpdate(info); try {
Alert.alert('提示', '下载完毕,是否重启应用?', [ const hash = await downloadUpdate(info, {
{ onDownloadProgress: ({received, total}) => {
text: '是', this.setState({
onPress: () => { received,
switchVersion(hash); total,
});
}, },
}, });
{text: '否'}, Alert.alert('提示', '下载完毕,是否重启应用?', [
{ {
text: '下次启动时', text: '',
onPress: () => { onPress: () => {
switchVersionLater(hash); switchVersion(hash);
},
}, },
}, {text: '否'},
]); {
text: '下次启动时',
onPress: () => {
switchVersionLater(hash);
},
},
]);
} catch (err) {
Alert.alert('更新失败', err.message);
}
}; };
checkUpdate = async () => { checkUpdate = async () => {
@@ -74,15 +90,33 @@ export default class App extends Component {
try { try {
info = await checkUpdate(appKey); info = await checkUpdate(appKey);
} catch (err) { } catch (err) {
console.warn(err); Alert.alert('更新检查失败', err.message);
return; return;
} }
if (info.expired) { if (info.expired) {
Alert.alert('提示', '您的应用版本已更新,请前往应用商店下载新的版本', [ Alert.alert('提示', '您的应用版本已更新,点击确定下载安装新版本', [
{ {
text: '确定', text: '确定',
onPress: () => { onPress: () => {
info.downloadUrl && Linking.openURL(info.downloadUrl); if (info.downloadUrl) {
// apk可直接下载安装
if (
Platform.OS === 'android' &&
info.downloadUrl.endsWith('.apk')
) {
downloadAndInstallApk({
url: info.downloadUrl,
onDownloadProgress: ({received, total}) => {
this.setState({
received,
total,
});
},
});
} else {
Linking.openURL(info.downloadUrl);
}
}
}, },
}, },
]); ]);
@@ -106,24 +140,29 @@ export default class App extends Component {
}; };
render() { render() {
const { received, total } = this.state;
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.welcome}>欢迎使用热更新服务</Text> <Text style={styles.welcome}>欢迎使用热更新服务</Text>
<Image <Image
resizeMode={'contain'} resizeMode={'contain'}
source={require('./assets/shoucang.png')} source={require('./assets/shezhi.png')}
style={styles.image} style={styles.image}
/> />
<Text style={styles.instructions}> <Text style={styles.instructions}>
这是版本一 {'\n'} 这是版本一 {'\n'}
当前包版本号: {packageVersion} 当前原生包版本号: {packageVersion}
{'\n'} {'\n'}
当前版本Hash: {currentVersion || '(空)'} 当前热更新版本Hash: {currentVersion || '(空)'}
{'\n'} {'\n'}
</Text> </Text>
<Text>
下载进度{received} / {total}
</Text>
<TouchableOpacity onPress={this.checkUpdate}> <TouchableOpacity onPress={this.checkUpdate}>
<Text style={styles.instructions}>点击这里检查更新</Text> <Text style={styles.instructions}>点击这里检查更新</Text>
</TouchableOpacity> </TouchableOpacity>
{/* <WebView style={{flex:1}} source={{uri: require('../www/index.html')}}/> */}
</View> </View>
); );
} }

22
Example/testHotUpdate/src/www/echarts.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- 引入 ECharts 文件 -->
<script src="echarts.min.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
# react-native-update [![npm version](https://badge.fury.io/js/react-native-update.svg)](http://badge.fury.io/js/react-native-update) # react-native-update [![npm version](https://badge.fury.io/js/react-native-update.svg)](http://badge.fury.io/js/react-native-update)
本组件是面向 React Native 提供热更新功能的组件,请结合[Update 服务](https://update.reactnative.cn/)使用 本组件是面向 React Native 提供热更新功能的组件,详情请访问我们的官方网站 <https://pushy.reactnative.cn>
### 快速开始 ### 快速开始
请查看[文档](https://reactnativecn.github.io/react-native-pushy) 请查看[文档](https://pushy.reactnative.cn/docs/getting-started.html)
### 优势 ### 优势

View File

@@ -1,7 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.reactnative.modules.update"> package="cn.reactnative.modules.update">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application> <application>
<meta-data android:name="pushy_build_time" android:value="@string/pushy_build_time" /> <meta-data android:name="pushy_build_time" android:value="@string/pushy_build_time" />
<provider
android:name=".PushyFileProvider"
android:authorities="${applicationId}.pushy.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/pushy_file_paths" />
</provider>
</application> </application>
</manifest> </manifest>

View File

@@ -41,6 +41,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
final int DOWNLOAD_CHUNK_SIZE = 4096; final int DOWNLOAD_CHUNK_SIZE = 4096;
Context context; Context context;
String hash;
DownloadTask(Context context) { DownloadTask(Context context) {
this.context = context; this.context = context;
@@ -69,7 +70,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
} }
} }
private void downloadFile(String url, File writePath) throws IOException { private void downloadFile(DownloadTaskParams param) throws IOException {
String url = param.url;
File writePath = param.targetFile;
this.hash = param.hash;
OkHttpClient client = new OkHttpClient(); OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url) Request request = new Request.Builder().url(url)
.build(); .build();
@@ -92,23 +96,25 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
} }
long bytesRead = 0; long bytesRead = 0;
long totalRead = 0; long received = 0;
double lastProgressValue=0; int currentPercentage = 0;
while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) { while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += bytesRead; received += bytesRead;
sink.emit(); sink.emit();
if (UpdateContext.DEBUG) { if (UpdateContext.DEBUG) {
Log.d("RNUpdate", "Progress " + totalRead + "/" + contentLength); Log.d("RNUpdate", "Progress " + received + "/" + contentLength);
} }
double progress = Math.round(((double) totalRead * 100) / contentLength);
if ((progress != lastProgressValue) || (totalRead == contentLength)) { int percentage = (int)(received * 100.0 / contentLength + 0.5);
lastProgressValue = progress; if (percentage > currentPercentage) {
publishProgress(new long[]{(long)progress,totalRead, contentLength}); currentPercentage = percentage;
publishProgress(new long[]{received, contentLength});
} }
} }
if (totalRead != contentLength) { if (received != contentLength) {
throw new Error("Unexpected eof while reading ppk"); throw new Error("Unexpected eof while reading downloaded update");
} }
publishProgress(new long[]{received, contentLength});
sink.writeAll(source); sink.writeAll(source);
sink.close(); sink.close();
@@ -121,10 +127,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
protected void onProgressUpdate(long[]... values) { protected void onProgressUpdate(long[]... values) {
super.onProgressUpdate(values); super.onProgressUpdate(values);
WritableMap params = Arguments.createMap(); WritableMap params = Arguments.createMap();
params.putDouble("progress", (values[0][0])); params.putDouble("received", (values[0][0]));
params.putDouble("totalRead", (values[0][1])); params.putDouble("total", (values[0][1]));
params.putDouble("contentLength", (values[0][2])); params.putString("hash", this.hash);
sendEvent("progress", params); sendEvent("RCTPushyDownloadProgress", params);
} }
@@ -237,10 +243,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
copyFilesWithBlacklist("", from, to, blackList); copyFilesWithBlacklist("", from, to, blackList);
} }
private void doDownload(DownloadTaskParams param) throws IOException { private void doFullPatch(DownloadTaskParams param) throws IOException {
downloadFile(param.url, param.zipFilePath); downloadFile(param);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath))); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
ZipEntry ze; ZipEntry ze;
String filename; String filename;
@@ -295,9 +301,9 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
} }
private void doPatchFromApk(DownloadTaskParams param) throws IOException, JSONException { private void doPatchFromApk(DownloadTaskParams param) throws IOException, JSONException {
downloadFile(param.url, param.zipFilePath); downloadFile(param);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath))); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
ZipEntry ze; ZipEntry ze;
int count; int count;
String filename; String filename;
@@ -371,9 +377,9 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
} }
private void doPatchFromPpk(DownloadTaskParams param) throws IOException, JSONException { private void doPatchFromPpk(DownloadTaskParams param) throws IOException, JSONException {
downloadFile(param.url, param.zipFilePath); downloadFile(param);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath))); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
ZipEntry ze; ZipEntry ze;
int count; int count;
String filename; String filename;
@@ -458,8 +464,8 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
protected Void doInBackground(DownloadTaskParams... params) { protected Void doInBackground(DownloadTaskParams... params) {
try { try {
switch (params[0].type) { switch (params[0].type) {
case DownloadTaskParams.TASK_TYPE_FULL_DOWNLOAD: case DownloadTaskParams.TASK_TYPE_PATCH_FULL:
doDownload(params[0]); doFullPatch(params[0]);
break; break;
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK: case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK:
doPatchFromApk(params[0]); doPatchFromApk(params[0]);
@@ -467,15 +473,23 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK: case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK:
doPatchFromPpk(params[0]); doPatchFromPpk(params[0]);
break; break;
case DownloadTaskParams.TASK_TYPE_CLEARUP: case DownloadTaskParams.TASK_TYPE_CLEANUP:
doCleanUp(params[0]); doCleanUp(params[0]);
break; break;
case DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD:
downloadFile(params[0]);
break;
default:
break;
}
if (params[0].listener != null) {
params[0].listener.onDownloadCompleted(params[0]);
} }
params[0].listener.onDownloadCompleted();
} catch (Throwable e) { } catch (Throwable e) {
if (UpdateContext.DEBUG) { if (UpdateContext.DEBUG) {
e.printStackTrace(); e.printStackTrace();
} }
Log.e("pushy", "download task failed", e);
params[0].listener.onDownloadFailed(e); params[0].listener.onDownloadFailed(e);
} }
return null; return null;

View File

@@ -8,17 +8,18 @@ import java.io.File;
* Created by tdzl2003 on 3/31/16. * Created by tdzl2003 on 3/31/16.
*/ */
class DownloadTaskParams { class DownloadTaskParams {
static final int TASK_TYPE_FULL_DOWNLOAD = 1; static final int TASK_TYPE_PATCH_FULL = 1;
static final int TASK_TYPE_PATCH_FROM_APK = 2; static final int TASK_TYPE_PATCH_FROM_APK = 2;
static final int TASK_TYPE_PATCH_FROM_PPK = 3; static final int TASK_TYPE_PATCH_FROM_PPK = 3;
static final int TASK_TYPE_PLAIN_DOWNLOAD = 4;
static final int TASK_TYPE_CLEARUP = 0; //Keep hash & originHash static final int TASK_TYPE_CLEANUP = 0; //Keep hash & originHash
int type; int type;
String url; String url;
String hash; String hash;
String originHash; String originHash;
File zipFilePath; File targetFile;
File unzipDirectory; File unzipDirectory;
File originDirectory; File originDirectory;
UpdateContext.DownloadFileListener listener; UpdateContext.DownloadFileListener listener;

View File

@@ -0,0 +1,14 @@
package cn.reactnative.modules.update;
import android.support.v4.content.FileProvider;
/**
* Providing a custom {@code FileProvider} prevents manifest {@code <provider>} name collisions.
*
* See https://developer.android.com/guide/topics/manifest/provider-element.html for details.
*/
public class PushyFileProvider extends FileProvider {
// This class intentionally left blank.
}

View File

@@ -7,6 +7,8 @@ import android.content.pm.PackageManager;
import android.util.Log; import android.util.Log;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@@ -21,8 +23,9 @@ public class UpdateContext {
private File rootDir; private File rootDir;
private Executor executor; private Executor executor;
public static boolean DEBUG = true; public static boolean DEBUG = false;
private static ReactInstanceManager mReactInstanceManager; private static ReactInstanceManager mReactInstanceManager;
private static boolean isUsingBundleUrl = false;
public UpdateContext(Context context) { public UpdateContext(Context context) {
this.context = context; this.context = context;
@@ -43,7 +46,7 @@ public class UpdateContext {
editor.putString("packageVersion", packageVersion); editor.putString("packageVersion", packageVersion);
editor.apply(); editor.apply();
this.clearUp(); this.cleanUp();
} }
} }
@@ -67,55 +70,81 @@ public class UpdateContext {
return context.getString(R.string.pushy_build_time); return context.getString(R.string.pushy_build_time);
} }
public String getUuid() {
return sp.getString("uuid", null);
}
public Map getBlockUpdate() {
return new HashMap<String, Object>() {{
put("until", sp.getInt("blockUntil", 0));
put("reason", sp.getString("blockReason", null));
}};
}
public boolean getIsUsingBundleUrl() {
return isUsingBundleUrl;
}
public interface DownloadFileListener { public interface DownloadFileListener {
void onDownloadCompleted(); void onDownloadCompleted(DownloadTaskParams params);
void onDownloadFailed(Throwable error); void onDownloadFailed(Throwable error);
} }
public void downloadFile(String url, String hashName, DownloadFileListener listener) { public void downloadFullUpdate(String url, String hash, DownloadFileListener listener) {
DownloadTaskParams params = new DownloadTaskParams(); DownloadTaskParams params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_FULL_DOWNLOAD; params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
params.url = url; params.url = url;
params.hash = hashName; params.hash = hash;
params.listener = listener; params.listener = listener;
params.zipFilePath = new File(rootDir, hashName + ".ppk"); params.targetFile = new File(rootDir, hash + ".ppk");
params.unzipDirectory = new File(rootDir, hashName); params.unzipDirectory = new File(rootDir, hash);
new DownloadTask(context).executeOnExecutor(this.executor, params); new DownloadTask(context).executeOnExecutor(this.executor, params);
} }
public void downloadPatchFromApk(String url, String hashName, DownloadFileListener listener) { public void downloadFile(String url, String hash, String fileName, DownloadFileListener listener) {
DownloadTaskParams params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
params.url = url;
params.hash = hash;
params.listener = listener;
params.targetFile = new File(rootDir, fileName);
// params.unzipDirectory = new File(rootDir, hash);
new DownloadTask(context).executeOnExecutor(this.executor, params);
}
public void downloadPatchFromApk(String url, String hash, DownloadFileListener listener) {
DownloadTaskParams params = new DownloadTaskParams(); DownloadTaskParams params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK; params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK;
params.url = url; params.url = url;
params.hash = hashName; params.hash = hash;
params.listener = listener; params.listener = listener;
params.zipFilePath = new File(rootDir, hashName + ".apk.patch"); params.targetFile = new File(rootDir, hash + ".apk.patch");
params.unzipDirectory = new File(rootDir, hashName); params.unzipDirectory = new File(rootDir, hash);
new DownloadTask(context).executeOnExecutor(this.executor, params); new DownloadTask(context).executeOnExecutor(this.executor, params);
} }
public void downloadPatchFromPpk(String url, String hashName, String originHashName, DownloadFileListener listener) { public void downloadPatchFromPpk(String url, String hash, String originHash, DownloadFileListener listener) {
DownloadTaskParams params = new DownloadTaskParams(); DownloadTaskParams params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK; params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
params.url = url; params.url = url;
params.hash = hashName; params.hash = hash;
params.originHash = originHashName; params.originHash = originHash;
params.listener = listener; params.listener = listener;
params.zipFilePath = new File(rootDir, originHashName + "-" + hashName + ".ppk.patch"); params.targetFile = new File(rootDir, originHash + "-" + hash + ".ppk.patch");
params.unzipDirectory = new File(rootDir, hashName); params.unzipDirectory = new File(rootDir, hash);
params.originDirectory = new File(rootDir, originHashName); params.originDirectory = new File(rootDir, originHash);
new DownloadTask(context).executeOnExecutor(this.executor, params); new DownloadTask(context).executeOnExecutor(this.executor, params);
} }
private SharedPreferences sp; private SharedPreferences sp;
public void switchVersion(String hashName) { public void switchVersion(String hash) {
if (!new File(rootDir, hashName+"/index.bundlejs").exists()) { if (!new File(rootDir, hash+"/index.bundlejs").exists()) {
throw new Error("Bundle version " + hashName + " not found."); throw new Error("Bundle version " + hash + " not found.");
} }
String lastVersion = getCurrentVersion(); String lastVersion = getCurrentVersion();
SharedPreferences.Editor editor = sp.edit(); SharedPreferences.Editor editor = sp.edit();
editor.putString("currentVersion", hashName); editor.putString("currentVersion", hash);
if (lastVersion != null) { if (lastVersion != null) {
editor.putString("lastVersion", lastVersion); editor.putString("lastVersion", lastVersion);
} }
@@ -125,6 +154,19 @@ public class UpdateContext {
editor.apply(); editor.apply();
} }
public void setUuid(String uuid) {
SharedPreferences.Editor editor = sp.edit();
editor.putString("uuid", uuid);
editor.apply();
}
public void setBlockUpdate(int until, String reason) {
SharedPreferences.Editor editor = sp.edit();
editor.putInt("blockUntil", until);
editor.putString("blockReason", reason);
editor.apply();
}
public String getCurrentVersion() { public String getCurrentVersion() {
return sp.getString("currentVersion", null); return sp.getString("currentVersion", null);
} }
@@ -143,7 +185,7 @@ public class UpdateContext {
editor.remove("lastVersion"); editor.remove("lastVersion");
editor.apply(); editor.apply();
this.clearUp(); this.cleanUp();
} }
public void clearFirstTime() { public void clearFirstTime() {
@@ -151,7 +193,7 @@ public class UpdateContext {
editor.putBoolean("firstTime", false); editor.putBoolean("firstTime", false);
editor.apply(); editor.apply();
this.clearUp(); this.cleanUp();
} }
public void clearRollbackMark() { public void clearRollbackMark() {
@@ -159,7 +201,7 @@ public class UpdateContext {
editor.putBoolean("rolledBack", false); editor.putBoolean("rolledBack", false);
editor.apply(); editor.apply();
this.clearUp(); this.cleanUp();
} }
@@ -184,6 +226,7 @@ public class UpdateContext {
} }
public String getBundleUrl(String defaultAssetsUrl) { public String getBundleUrl(String defaultAssetsUrl) {
isUsingBundleUrl = true;
String currentVersion = getCurrentVersion(); String currentVersion = getCurrentVersion();
if (currentVersion == null) { if (currentVersion == null) {
return defaultAssetsUrl; return defaultAssetsUrl;
@@ -224,21 +267,12 @@ public class UpdateContext {
return lastVersion; return lastVersion;
} }
private void clearUp() { private void cleanUp() {
DownloadTaskParams params = new DownloadTaskParams(); DownloadTaskParams params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_CLEARUP; params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
params.hash = sp.getString("currentVersion", null); params.hash = sp.getString("currentVersion", null);
params.originHash = sp.getString("lastVersion", null); params.originHash = sp.getString("lastVersion", null);
params.unzipDirectory = rootDir; params.unzipDirectory = rootDir;
params.listener = new DownloadFileListener() {
@Override
public void onDownloadCompleted() {
}
@Override
public void onDownloadFailed(Throwable error) {
}
};
new DownloadTask(context).executeOnExecutor(this.executor, params); new DownloadTask(context).executeOnExecutor(this.executor, params);
} }
} }

View File

@@ -3,6 +3,8 @@ package cn.reactnative.modules.update;
import android.app.Activity; import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log; import android.util.Log;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
@@ -18,21 +20,25 @@ import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static android.support.v4.content.FileProvider.getUriForFile;
/** /**
* Created by tdzl2003 on 3/31/16. * Created by tdzl2003 on 3/31/16.
*/ */
public class UpdateModule extends ReactContextBaseJavaModule{ public class UpdateModule extends ReactContextBaseJavaModule {
UpdateContext updateContext; UpdateContext updateContext;
public static ReactApplicationContext mContext; public static ReactApplicationContext mContext;
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) { public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
super(reactContext); super(reactContext);
this.updateContext = updateContext; this.updateContext = updateContext;
mContext=reactContext; mContext = reactContext;
} }
public UpdateModule(ReactApplicationContext reactContext) { public UpdateModule(ReactApplicationContext reactContext) {
@@ -46,6 +52,7 @@ public class UpdateModule extends ReactContextBaseJavaModule{
constants.put("packageVersion", updateContext.getPackageVersion()); constants.put("packageVersion", updateContext.getPackageVersion());
constants.put("currentVersion", updateContext.getCurrentVersion()); constants.put("currentVersion", updateContext.getCurrentVersion());
constants.put("buildTime", updateContext.getBuildTime()); constants.put("buildTime", updateContext.getBuildTime());
constants.put("isUsingBundleUrl", updateContext.getIsUsingBundleUrl());
boolean isFirstTime = updateContext.isFirstTime(); boolean isFirstTime = updateContext.isFirstTime();
constants.put("isFirstTime", isFirstTime); constants.put("isFirstTime", isFirstTime);
if (isFirstTime) { if (isFirstTime) {
@@ -56,6 +63,8 @@ public class UpdateModule extends ReactContextBaseJavaModule{
if (isRolledBack) { if (isRolledBack) {
updateContext.clearRollbackMark(); updateContext.clearRollbackMark();
} }
constants.put("blockUpdate", updateContext.getBlockUpdate());
constants.put("uuid", updateContext.getUuid());
return constants; return constants;
} }
@@ -65,12 +74,12 @@ public class UpdateModule extends ReactContextBaseJavaModule{
} }
@ReactMethod @ReactMethod
public void downloadUpdate(ReadableMap options, final Promise promise){ public void downloadUpdate(ReadableMap options, final Promise promise) {
String url = options.getString("updateUrl"); String url = options.getString("updateUrl");
String hash = options.getString("hashName"); String hash = options.getString("hash");
updateContext.downloadFile(url, hash, new UpdateContext.DownloadFileListener() { updateContext.downloadFullUpdate(url, hash, new UpdateContext.DownloadFileListener() {
@Override @Override
public void onDownloadCompleted() { public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null); promise.resolve(null);
} }
@@ -82,12 +91,61 @@ public class UpdateModule extends ReactContextBaseJavaModule{
} }
@ReactMethod @ReactMethod
public void downloadPatchFromPackage(ReadableMap options, final Promise promise){ public void downloadAndInstallApk(ReadableMap options, final Promise promise) {
String url = options.getString("url");
String hash = options.getString("hash");
String target = options.getString("target");
updateContext.downloadFile(url, hash, target, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted(DownloadTaskParams params) {
installApk(params.targetFile);
promise.resolve(null);
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);
}
});
}
// install downloaded apk
@ReactMethod
public static void installApk(String url) {
File toInstall = new File(url);
installApk(toInstall);
}
public static void installApk(File toInstall) {
Uri apkUri;
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
apkUri = getUriForFile(mContext, mContext.getPackageName() + ".pushy.fileprovider", toInstall);
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} else {
apkUri = Uri.fromFile(toInstall);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
@ReactMethod
public void downloadPatchFromPackage(ReadableMap options, final Promise promise) {
String url = options.getString("updateUrl"); String url = options.getString("updateUrl");
String hash = options.getString("hashName"); String hash = options.getString("hash");
if (hash == null) {
hash = options.getString("hashName");
}
updateContext.downloadPatchFromApk(url, hash, new UpdateContext.DownloadFileListener() { updateContext.downloadPatchFromApk(url, hash, new UpdateContext.DownloadFileListener() {
@Override @Override
public void onDownloadCompleted() { public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null); promise.resolve(null);
} }
@@ -99,13 +157,19 @@ public class UpdateModule extends ReactContextBaseJavaModule{
} }
@ReactMethod @ReactMethod
public void downloadPatchFromPpk(ReadableMap options, final Promise promise){ public void downloadPatchFromPpk(ReadableMap options, final Promise promise) {
String url = options.getString("updateUrl"); String url = options.getString("updateUrl");
String hash = options.getString("hashName"); String hash = options.getString("hash");
String originHash = options.getString("originHashName"); if (hash == null) {
hash = options.getString("hashName");
}
String originHash = options.getString("originHash");
if (originHash == null) {
originHash = options.getString(("originHashName"));
}
updateContext.downloadPatchFromPpk(url, hash, originHash, new UpdateContext.DownloadFileListener() { updateContext.downloadPatchFromPpk(url, hash, originHash, new UpdateContext.DownloadFileListener() {
@Override @Override
public void onDownloadCompleted() { public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null); promise.resolve(null);
} }
@@ -118,7 +182,8 @@ public class UpdateModule extends ReactContextBaseJavaModule{
@ReactMethod @ReactMethod
public void reloadUpdate(ReadableMap options) { public void reloadUpdate(ReadableMap options) {
final String hash = options.getString("hashName"); final String hash = options.getString("hash") == null ?
options.getString("hashName") : options.getString("hash");
UiThreadUtil.runOnUiThread(new Runnable() { UiThreadUtil.runOnUiThread(new Runnable() {
@Override @Override
@@ -134,19 +199,19 @@ public class UpdateModule extends ReactContextBaseJavaModule{
} }
try { try {
Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
jsBundleField.setAccessible(true);
jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
} catch (Throwable err) {
JSBundleLoader loader = JSBundleLoader.createFileLoader(UpdateContext.getBundleUrl(application)); JSBundleLoader loader = JSBundleLoader.createFileLoader(UpdateContext.getBundleUrl(application));
Field loadField = instanceManager.getClass().getDeclaredField("mBundleLoader"); Field loadField = instanceManager.getClass().getDeclaredField("mBundleLoader");
loadField.setAccessible(true); loadField.setAccessible(true);
loadField.set(instanceManager, loader); loadField.set(instanceManager, loader);
} catch (Throwable err) {
Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
jsBundleField.setAccessible(true);
jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
} }
try { try {
instanceManager.recreateReactContextInBackground(); instanceManager.recreateReactContextInBackground();
} catch(Throwable err) { } catch (Throwable err) {
activity.recreate(); activity.recreate();
} }
@@ -159,7 +224,8 @@ public class UpdateModule extends ReactContextBaseJavaModule{
@ReactMethod @ReactMethod
public void setNeedUpdate(ReadableMap options) { public void setNeedUpdate(ReadableMap options) {
final String hash = options.getString("hashName"); final String hash = options.getString("hash") == null ?
options.getString("hashName") : options.getString("hash");
UiThreadUtil.runOnUiThread(new Runnable() { UiThreadUtil.runOnUiThread(new Runnable() {
@Override @Override
@@ -183,8 +249,30 @@ public class UpdateModule extends ReactContextBaseJavaModule{
}); });
} }
@ReactMethod
public void setBlockUpdate(ReadableMap options) {
final int until = options.getInt("until");
final String reason = options.getString("reason");
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
updateContext.setBlockUpdate(until, reason);
}
});
}
@ReactMethod
public void setUuid(final String uuid) {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
updateContext.setUuid(uuid);
}
});
}
/* 发送事件*/ /* 发送事件*/
public static void sendEvent(String eventName, WritableMap params) { public static void sendEvent(String eventName, WritableMap params) {
((ReactContext) mContext).getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, ((ReactContext) mContext).getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,
params); params);
} }

View File

@@ -0,0 +1,5 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="pushy"
path="." />
</paths>

View File

View File

@@ -1,53 +0,0 @@
# react-native-update [![npm version](https://badge.fury.io/js/react-native-update.svg)](http://badge.fury.io/js/react-native-update)
本组件是面向 React Native 提供热更新功能的组件,请结合[Update 服务](https://update.reactnative.cn/)使用。
<details>
<summary>
注意,在 iOS 上使用热更新有被拒的可能。被拒之后可以按此步骤单独屏蔽 iOS 端(`react-native-update`版本需 >= 5.3.2)
</summary>
1. 如果 RN 版本>=0.60,在项目根目录下编辑或创建 react-native.config.js添加如下内容
```js
// react-native.config.js
module.exports = {
dependencies: {
'react-native-update': {
platforms: {
ios: null, // 阻止ios模块自动链接
},
},
},
};
```
2. 如果在原生代码端尚未配置,则跳过下面文档中的 ios 端的配置。如果已经配置,则按文档的步骤反向操作(添加的 ios 代码删去)。
3. 如果是 0.60 以上版本或使用了 cocoapods在 ios 目录中再次运行 pod install确保 Podfile 和 Podfile.lock 中都没有'react-native-update'。如果 RN 版本<0.60则运行`react-native unlink react-native-update`
4. js 代码里调用 checkUpdate()方法前判断 Platform.OS如果是 ios 平台则直接 return 跳过
</details>
### 优势
1. 命令行工具&网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
2. 基于 bsdiff 算法创建的**超小更新包**,通常版本迭代后在 1-10KB 之间,避免数百 KB 的流量消耗。
3. 支持崩溃回滚,安全可靠。
4. meta 信息及开放 API提供更高扩展性。
5. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
### 本地开发
```
$ git clone git@github.com:reactnativecn/react-native-pushy.git
$ cd react-native-pushy/Example/testHotUpdate
$ yarn
$ yarn start
```
本地库文件使用 yarn link 链接,因此可直接在源文件中修改,在 testHotUpdate 项目中调试。
### 关于我们
本组件由[React Native 中文网](https://reactnative.cn/)独家发布,如有定制需求可以[联系我们](https://reactnative.cn/about.html#content)。
关于此插件发现任何问题,可以前往[Issues](https://github.com/reactnativecn/react-native-pushy/issues)或者[中文社区](http://bbs.reactnative.cn/category/7)发帖提问。

View File

@@ -1,10 +0,0 @@
- 安装与快速入门
- [准备工作](guide.md)
- [添加热更新功能](guide2.md)
- [发布版本](guide3.md)
- [常见问题与高级指南](faq_advance.md)
- [API接口](api.md)
- [命令行工具](cli.md)
- [最近更新](changelog.md)

View File

@@ -1,65 +0,0 @@
# API
### downloadRootDir
下载的根目录。你可以使用react-native-fs等第三方组件检查其中的内容。
### packageVersion
当前应用原生包的版本。其中android取自`versionName`字段(位于`android/build.gralde`中)。ios取自`CFBundleShortVersionString`字段(位于`ios/项目名/Info.plist`中)。
### currentVersion
当前热更新版本jsbundle文件的Hash号。
### isFirstTime
是否更新后的首次启动。当此项为真时,你需要在合适的时候调用`markSuccess()`以确保更新成功。否则应用下一次启动时将会回滚。
### isRolledBack
是否刚刚经历了一次回滚。
### async function checkUpdate(appKey)
检查更新,返回值有三种情形:
1. `{expired: true}`:该应用原生包已过期,需要前往应用市场下载新的版本。
```
{
expired: true,
downloadUrl: 'http://appstore/downloadUrl',
}
```
2. `{upToDate: true}`:当前已经更新到最新,无需进行更新。
3. `{update: true}`当前有新版本可以更新。info的`name``description`字段可
以用于提示用户,而`metaInfo`字段则可以根据你的需求自定义其它属性(如是否静默更新、
是否强制更新等等)。另外还有几个字段,包含了热更新文件的下载地址,
```
{
update: true,
name: '1.0.3-rc',
hash: 'hash',
description: '添加聊天功能\n修复商城页面BUG',
metaInfo: '{"silent":true}',
pdiffUrl: 'http://update-packages.reactnative.cn/hash',
diffUrl: 'http://update-packages.reactnative.cn/hash',
}
```
### async function downloadUpdate(info)
下载更新版本。info为checkUpdate函数的返回值并且仅当`update:true`时实际进行下载。
### function switchVersion(hash)
立即重启应用,并加载已经下载完毕的版本。
### function switchVersionLater(hash)
在下一次启动应用的时候加载已经下载完毕的版本。
### function markSuccess()
在isFirstTime为true时需在应用成功启动后调用此函数

View File

@@ -1,87 +0,0 @@
### 最近更新
## 5.5.6 (2020-02-11)
1. bundle时清除缓存
2. 修复更新包过大时可能出现的崩溃
3. publish时检查文件格式
## 5.5.5 (2020-01-18)
1. 提升服务健壮性
## 5.5.4 (2020-01-13)
1. 防止某些情况下安卓找不到bundle文件引起的崩溃
## 5.5.3 (2019-12-18)
1. 忽略hermes的输出避免buffer溢出
## 5.5.2 (2019-12-06)
1. 修复使用use_frameworks时无法读取时间戳的问题
## 5.5.0 (2019-11-24)
1. 打包时加入时间戳
## 5.4.0 (2019-11-16)
1. 修改类名方法名
## 5.3.2 (2019-10-25)
1. 可以禁用ios端以避免审核被拒
## 5.3.0 (2019-09-19)
1. 替换 apk reader 以避免某些环境读取 apk 版本号报错的问题
## 5.2.9 (2019-09-18)
1. 添加 proguard 混淆规则以解决开启混淆后闪退的问题
## 5.2.8
1. 解决某些情形下 Android 调用 switchVersion 不能重启的问题
## 5.2.7
1. 改进 windows 端打更新包的兼容性(部分 windows 机器上会产生空 ppk 文件)
## 5.2.4
1. 支持 RN 0.61 的 hermes路径变化
2. iOS 端使用第三方的 SSZipArchive 以减少重名冲突
## 5.2.2
1. 修复一处导致 iOS 回滚的问题
## 5.2.1
1. 检测如果开启了 hermes则自动编译为 hermes 字节码格式
## 5.2.0
1. 添加 typescript 声明
2. 支持 cocoapods
## 5.1.9
1. 重写 bundle 命令以提升版本兼容性
2. 改进命令行的输出样式
## 5.1.8
1. 服务器迁移到 https
2. android 支持 64 位
## 5.1.6
解决 Android 热更新后部分图片丢失问题:
同一个项目中放置了多个完全相同的文件,在 5.1.0 至 5.1.5 之间的版本中,更新后有时会出现其中的部分无法显示。此问题在 5.1.6 版本修复。
修复此问题涉及原生部分,需要重新打包。

View File

@@ -1,118 +0,0 @@
# 命令行工具
## 安装
```
$ npm install -g react-native-update-cli
$ npm install react-native-update
```
## 使用
#### pushy bundle
生成资源包
* platform: ios|android 对应的平台
* entryFile: 入口脚本文件
* intermediaDir: 临时文件输出目录
* output: 最终ppk文件输出路径
* dev: 是否打包开发版本
* verbose: 是否展现打包过程的详细信息
#### pushy diff <origin> <next>
提供两个ppk文件生成从origin到next版本的差异更新包。
* output: diff文件输出路径
#### pushy diffFromApk <apkFile> <next>
提供一个apk文件和一个ppk文件生成从apk文件到next版本的差异更新包。
如果使用热更新开放平台,你不需要自己执行此命令。
* output: diff文件输出路径
#### pushy diffFromIpa <ipaFile> <next>
提供一个ipa文件和一个ppk文件生成从ipa文件到next版本的差异更新包。
如果使用热更新开放平台,你不需要自己执行此命令。
* output: diff文件输出路径
#### pushy login [<email>] [<pwd>]
登录热更新开放平台。你需要先登录才能使用下面的命令。
#### pushy logout
登出并清除本地的登录信息
#### pushy me
查看自己是否已经登录,以及昵称等信息。
#### pushy createApp
创建应用并立刻绑定到当前工程。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
- name: 应用名称
- downloadUrl: 应用安装包的下载地址
#### pushy deleteApp [appId]
删除已有应用。所有已创建的应用包、热更新版本都会被同时删除。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
#### pushy apps
查看当前已创建的全部应用。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
#### pushy selectApp [appId]
绑定应用到当前工程。
- platform: ios|android 对应的平台
#### pushy uploadIpa <ipaFile>
上传 ipa 文件到开放平台。
#### pushy uploadApk <apkFile>
上传 apk 文件到开放平台。
#### pushy packages
查看已经上传的原生包。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
#### pushy publish <ppkFile>
发布新的热更新版本ppk文件
- platform: ios|android 对应的平台
- name: 当前热更新版本的名字(版本号)
- description: 当前热更新版本的描述信息,可以对用户进行展示
- metaInfo: 当前热更新版本的元信息,可以用来保存一些额外信息
#### pushy versions
分页列举可用的版本。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
#### pushy update
为一个原生包版本绑定一个热更新版本。这项操作也可以在网页管理端进行。
- platform: ios|android 对应的平台
- versionId: 要绑定的热更新版本 ID
- packageId: 要绑定的原生包 ID

View File

@@ -1,71 +0,0 @@
## 常见问题
#### 报错 NDK not configured.
你需要下载并安装NDK然后设置到环境变量`ANDROID_NDK_HOME`中。
#### 报错 Execution failed for task ':react-native-update:compileReleaseNdk'
参看 https://github.com/reactnativecn/react-native-pushy/issues/64#issuecomment-287967742
 
#### iOS报错 Unable to execute JS call: __fbBatchedBridge is undefined
如果直接修改了jsCodeLocation将不能在iOS模拟器上运行。可以使用真机测试。要在发布之前测试热更新功能可以用adhoc方式发布测试包并进行测试。adhoc发布的包可以用于uploadIpa和生成差异包。
#### XCode报错 "_BZ2_bzRead", referenced from 等
在工程target的Build Phases->Link Binary with Libraries中加入libz.tbd、libbz2.1.0.tbd
## 高级指南
#### 过期的版本
你可以删除掉过期很久的版本。在一段时间后,版本会被真正清理。
如果有用户还处在已经被清理的版本上,当他发起更新的时候,将不能通过版本差异比对进行更新,即只能进行全量更新。
#### CI的集成
在开发环境中每次bundle都会生成一个不同名字的ppk文件这不利于持续集成(CI)系统的引入。
要解决这个问题,你可以使用`--output`参数来指定输出ppk文件的名字和路径便于进行自动发布。
#### 版本测试与发布
我们强烈建议您先发布一个测试包,再发布一个除了版本号以外均完全相同的发布包。
在每次往发布包发起热更新之前,先往对应的测试包进行更新操作,基本测试通过之后,可以将发布包更新到完全相同的热更新版本之上。
如果在测试包中发现了重大问题,你就可以先进行修复,再次更新测试通过后,再将发布包更新至修复后的版本。
这样,可以最大程度的避免用户通过热更新获得一个有问题的版本。
#### 元信息(Meta Info)的使用
在发布热更新版本时,或者在网页端,你可以编辑版本的元信息。
这是一段在检查更新时可以获得的字符串,你可以在其中按你所想的格式保存一些信息。
举例来说,可能某个版本包含一些重要的更新内容,所以用户会得到一个不同样式的通知。如何使用元信息,完全取决于您的想象力!
下面会列举一些实战中更有意义的元信息的使用。
#### Hot-fix
有时候我们不小心发布了一个有严重问题的版本,所以需要进行一个紧急的修复,
此时我们可能希望之前已经更新到有问题版本的用户进行紧急甚至静默进行更新。
这时候,我们可以在元信息中包含有问题的版本的列表,而在客户端检查更新时,将从元信息里取到的列表与当前版本(currentVersion)比对,
如果匹配成功,我们就进行静默更新,否则则按照一般的更新流程提示用户。
#### 这个热更新服务收费吗?
目前我们的热更新服务完全免费但限制每个账号不超过3个应用每个应用不超过10个活跃的包和100个活跃的热更新版本每个应用每个月不超过10000次下载。iOS和Android版本记做不同的应用。
已经移除的应用、原生包版本、热更新版本不在统计之列,所以你可以移除测试时产生的和已过期版本来更有效的利用空间。
我们会在将来推出付费的升级版本,针对用户量较大、版本迭代较快的用户提供扩容方案。如果您有急迫的需求,可以[联系我们](https://reactnative.cn/about.html#content)。
#### 我是否可以搭建自己的热更新服务?
你可以单独使用本组件的原生部分(不包括js模块)和命令行工具中的`bundle``diff``diffFromIpa``diffFromApk`四个功能。
这些功能都不会使用我们的热更新服务也无需注册或登录账号。但你可能要编写自己的js模块来与不同的热更新服务器通讯。
如果您有兴趣使用我们的成果,搭建私有云服务,可以[联系我们](https://reactnative.cn/about.html#content)。

View File

@@ -1,228 +0,0 @@
# 快速入门-准备工作
首先你应该有一个基于React Native开发的应用我们把具有package.json的目录叫做你的"应用根目录"。
如果你还没有初始化应用,请参阅[开始使用React Native](https://reactnative.cn/docs/getting-started.html#content)。
所以我们也假设你已经拥有了开发React Native应用的一切环境包括`Node.js``npm``XCode``Android SDK`等等。
## 安装
在你的项目根目录下运行以下命令:
```bash
npm i -g react-native-update-cli
npm i react-native-update
```
> 如果下载极慢或者显示网络失败,请设置使用淘宝镜像`npx nrm use taobao`
如果你的RN版本 >= 0.60请在iOS目录下执行:
```bash
pod install
```
如果你的RN版本 < 0.60那么还需要[手动link](#一手动link)
<details>
<summary>
如果你的RN版本比较老< 0.46请点击这里的注意事项
</summary>
如果你的RN版本比较老请按下面表格尝试老一些的版本但这些版本我们已不再维护不能保证可以使用
| React Native版本 | react-native-update版本 |
| ---------------- | ----------------------- |
| 0.26及以下 | 1.0.x |
| 0.27 - 0.28 | 2.x |
| 0.29 - 0.33 | 3.x |
| 0.34 - 0.45 | 4.x |
安装命令示例:
```
npm i react-native-update@4.x
```
如果RN的版本是0.45及以下,你还必须安装[Android NDK](http://androiddevtools.cn)版本最好选用r10e并设置环境变量`ANDROID_NDK_HOME`指向你的NDK根目录(例如`/Users/tdzl2003/Downloads/android-ndk-r10e`)。
</details>
请记得一定要重新编译react-native run-ios或run-android命令编译或在Xcode/Android Studio中重新编译
## 手动link
如果RN版本 >= 0.60则可以跳过此步骤
### iOS
<details>
<summary>RN < 0.60且使用CocoaPods推荐</summary>
1. 在ios/Podfile中添加
```
pod 'react-native-update', path: '../node_modules/react-native-update'
```
2. 在项目的ios目录下运行`pod install`
3. 重新编译
</details>
<details>
<summary>RN < 0.60且不使用CocoaPods</summary>
1. 在XCode中的Project Navigator里,右键点击`Libraries``Add Files to [你的工程名]`
2. 进入`node_modules``react-native-update``ios 并选中 `RCTPushy.xcodeproj`
3. 在XCode中的project navigator里,选中你的工程,在 `Build Phases``Link Binary With Libraries` 中添加 `libRCTPushy.a`
4. 继续在`Build Settings`里搜索`Header Search Path`,添加$(SRCROOT)/../node_modules/react-native-update/ios
5.`Build Phases`添加一个`New Run Script Phase`运行脚本,内容如下
```
#!/bin/bash
set -x
DEST="../node_modules/react-native-update/ios/"
date +%s > "$DEST/pushy_build_time.txt"
```
编译的时候就会在`../node_modules/react-native-update/ios/`文件夹下面生成一个`pushy_build_time.txt`文件。
然后在`Copy Bundle Resources`里把生成的`pushy_build_time.txt`文件添加进去。
6. 重新编译
</details>
### Android
<details>
<summary>RN < 0.60</summary>
1.`android/settings.gradle`中添加如下代码:
```
include ':react-native-update'
project(':react-native-update').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-update/android')
```
2. 在`android/app/build.gradle`的 dependencies 部分增加如下代码:
```
implementation project(':react-native-update')
```
3. 打开`android/app/src/main/java/[...]/MainApplication.java`,
- 在文件开头增加 `import cn.reactnative.modules.update.UpdatePackage;`
- 在`getPackages()` 方法中增加 `new UpdatePackage()`(注意上一行可能要增加一个逗号)
</details>
## 配置Bundle URL
注意此步骤无论任何版本,目前都需要手动配置。
### iOS
1. (RN >= 0.60或者使用CocoaPods集成此步可跳过)在工程target的Build Phases->Link Binary with Libraries中加入`libz.tbd`、`libbz2.1.0.tbd`
2. 在你的AppDelegate.m文件中增加如下代码
```objective-c
// ... 其它代码
#import "RCTPushy.h"
// 如果RN版本 >= 0.59修改sourceURLForBridge
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
 // 非DEBUG情况下替换为热更新bundle
return [RCTPushy bundleURL];
#endif
}
// 如果RN版本 < 0.59修改didFinishLaunchingWithOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
 // 原来的jsCodeLocation保留在这里
 jsCodeLocation = ..........
#else
 // 非DEBUG情况下替换为热更新bundle
 jsCodeLocation = [RCTPushy bundleURL];
#endif
// ... 其它代码
}
```
### Android
在MainApplication中增加如下代码
```java
// ... 其它代码
// 请注意不要少了这句import
import cn.reactnative.modules.update.UpdateContext;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(MainApplication.this);
}
// ... 其它代码
}
}
```
## 登录与创建应用
首先请在<https://update.reactnative.cn>注册帐号,然后在你的项目根目录下运行以下命令:
```bash
$ pushy login
email: <输入你的注册邮箱>
password: <输入你的密码>
```
这会在项目文件夹下创建一个`.update`文件注意不要把这个文件上传到Git等CVS系统上。你可以在`.gitignore`末尾增加一行`.update`来忽略这个文件。
登录之后可以创建应用。注意iOS平台和安卓平台需要分别创建
```bash
$ pushy createApp --platform ios
App Name: <输入应用名字>
$ pushy createApp --platform android
App Name: <输入应用名字>
```
> 两次输入的名字可以相同,这没有关系。
如果你已经在网页端或者其它地方创建过应用,也可以直接选择应用:
```bash
$ pushy selectApp --platform ios
1) 鱼多多(ios)
2) 招财旺(ios)
Total 2 ios apps
Enter appId: <输入应用前面的编号>
```
选择或者创建过应用后,你将可以在文件夹下看到`update.json`文件,其内容类似如下形式:
```bash
{
"ios": {
"appId": 1,
"appKey": "<一串随机字符串>"
},
"android": {
"appId": 2,
"appKey": "<一串随机字符串>"
}
}
```
你可以安全的把`update.json`上传到Git等CVS系统上与你的团队共享这个文件它不包含任何敏感信息。当然他们在使用任何功能之前都必须首先输入`pushy login`进行登录。
至此应用的创建/选择就已经成功了。下一步,你需要给代码添加相应的功能,请参阅[添加热更新功能](guide2.md)

View File

@@ -1,177 +0,0 @@
# 快速入门-添加热更新功能
## 获取appKey
检查更新时必须提供你的`appKey`,这个值保存在`update.json`中,并且根据平台不同而不同。你可以用如下的代码获取:
```javascript
import {
Platform,
} from 'react-native';
import _updateConfig from './update.json';
const {appKey} = _updateConfig[Platform.OS];
```
如果你不使用pushy命令行你也可以从网页端查看到两个应用appKey并根据平台的不同来选择。
## 检查更新、下载更新
异步函数checkUpdate可以检查当前版本是否需要更新
```javascript
const info = await checkUpdate(appKey)
```
返回的info有三种情况
1. `{expired: true}`该应用原生包已过期已从pushy服务器中删除开发者应该在pushy控制台添加一个更新下载链接并自行提示用户下载。
2. `{upToDate: true}`:当前已经更新到最新,无需进行更新。
3. `{update: true}`当前有新版本可以更新。info的`name``description`字段可
以用于提示用户,而`metaInfo`字段则可以根据你的需求自定义其它属性(如是否静默更新、
是否强制更新等等)。另外还有几个字段,包含了完整更新包或补丁包的下载地址,
react-native-update会首先尝试耗费流量更少的更新方式。将info对象传递给downloadUpdate作为参数即可。
## 切换版本
downloadUpdate的返回值是一个hash字符串它是当前热更新版本的唯一标识。
你可以使用`switchVersion`函数立即切换版本(此时应用会立即重新加载),或者选择调用
`switchVersionLater`,让应用在下一次启动的时候再加载新的版本。
## 首次启动、回滚
在每次更新完毕后的首次启动时,`isFirstTime`常量会为`true`
你必须在应用退出前合适的任何时机,调用`markSuccess`,否则应用下一次启动的时候将会进行回滚操作。
这一机制称作“反触发”,这样当你应用启动初期即遭遇问题的时候,也能在下一次启动时恢复运作。
你可以通过`isFirstTime`来获知这是当前版本的首次启动,也可以通过`isRolledBack`来获知应用刚刚经历了一次回滚操作。
你可以在此时给予用户合理的提示。
## 完整的示例
```javascript
import React, {
Component,
} from 'react';
import {
AppRegistry,
StyleSheet,
Platform,
Text,
View,
Alert,
TouchableOpacity,
Linking,
} from 'react-native';
import {
isFirstTime,
isRolledBack,
packageVersion,
currentVersion,
checkUpdate,
downloadUpdate,
switchVersion,
switchVersionLater,
markSuccess,
} from 'react-native-update';
import _updateConfig from './update.json';
const {appKey} = _updateConfig[Platform.OS];
class MyProject extends Component {
componentDidMount(){
if (isFirstTime) {
Alert.alert('提示', '这是当前版本第一次启动,是否要模拟启动失败?失败将回滚到上一版本', [
{text: '是', onPress: ()=>{throw new Error('模拟启动失败,请重启应用')}},
{text: '否', onPress: ()=>{markSuccess()}},
]);
} else if (isRolledBack) {
Alert.alert('提示', '刚刚更新失败了,版本被回滚.');
}
}
doUpdate = async (info) => {
try {
const hash = await downloadUpdate(info);
Alert.alert('提示', '下载完毕,是否重启应用?', [
{text: '是', onPress: ()=>{switchVersion(hash);}},
{text: '否',},
{text: '下次启动时', onPress: ()=>{switchVersionLater(hash);}},
]);
} catch(err) {
Alert.alert('提示', '更新失败.');
}
};
checkUpdate = async () => {
if (__DEV__) {
// 开发模式不支持热更新,跳过检查
return;
}
let info;
try {
info = await checkUpdate(appKey);
} catch (err) {
console.warn(err);
return;
}
if (info.expired) {
Alert.alert('提示', '您的应用版本已更新,请前往应用商店下载新的版本', [
{text: '确定', onPress: ()=>{info.downloadUrl && Linking.openURL(info.downloadUrl)}},
]);
} else if (info.upToDate) {
Alert.alert('提示', '您的应用版本已是最新.');
} else {
Alert.alert('提示', '检查到新的版本'+info.name+',是否下载?\n'+ info.description, [
{text: '是', onPress: ()=>{this.doUpdate(info)}},
{text: '否',},
]);
}
};
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
欢迎使用热更新服务
</Text>
<Text style={styles.instructions}>
这是版本一 {'\n'}
当前原生包版本号: {packageVersion}{'\n'}
当前热更新版本Hash: {currentVersion||'(空)'}{'\n'}
</Text>
<TouchableOpacity onPress={this.checkUpdate}>
<Text style={styles.instructions}>
点击这里检查更新
</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('MyProject', () => MyProject);
```
现在你的应用已经可以通过update服务检查版本并进行更新了。下一步你可以开始尝试发布应用包和版本请参阅[发布应用](guide3.md)

View File

@@ -1,80 +0,0 @@
# 快速入门-发布应用
现在你的应用已经具备了检测更新的功能,下面我们来尝试发布并更新它。
> **注意**从update上传发布版本到发布版本正式上线期间不要修改任何脚本和资源这会影响update
获取本地代码,从而导致版本不能更新。如果在发布之前修改了脚本或资源,请在网页端删除之前上传的版本并重新上传。
## 发布iOS应用
首先参考[文档-在设备上运行](https://reactnative.cn/docs/running-on-device-ios.html#content)
确定你正在使用离线包。然后点击菜单。
按照正常的发布流程打包`.ipa`文件(Xcode中运行设备选真机或Generic iOS Device然后菜单中选择Product-Archive),然后运行如下命令
```bash
$ pushy uploadIpa <your-package.ipa>
```
即可上传ipa以供后续版本比对之用。此ipa的`CFBundleShortVersionString`字段(位于`ios/项目名/Info.plist`中)会被记录为原生版本号`packageVersion`
随后你可以选择往AppStore发布这个版本也可以先通过Test flight等方法进行测试。
## 发布安卓应用
首先参考[文档-生成已签名的APK](https://reactnative.cn/docs/signed-apk-android.html#content)设置签名,
然后在android文件夹下运行`./gradlew assembleRelease``./gradlew aR`,你就可以在`android/app/build/outputs/apk/release/app-release.apk`中找到你的应用包。
然后运行如下命令
```bash
$ pushy uploadApk android/app/build/outputs/apk/release/app-release.apk
```
即可上传apk以供后续版本比对之用。此apk的`versionName`字段(位于`android/build.gralde`中)会被记录为原生版本号`packageVersion`
随后你可以选择往应用市场发布这个版本也可以先往设备上直接安装这个apk文件以进行测试。
## 发布新的热更新版本
你可以尝试修改一行代码(譬如将版本一修改为版本二),然后生成新的热更新版本。
```bash
$ pushy bundle --platform <ios|android>
Bundling with React Native version: 0.22.2
<各种进度输出>
Bundled saved to: build/output/android.1459850548545.ppk
Would you like to publish it?(Y/N)
```
如果想要立即发布此时输入Y。当然你也可以在将来使用`pushy publish --platform <ios|android> <ppkFile>`来发布版本。
```
Uploading [========================================================] 100% 0.0s
Enter version name: <输入热更新版本名字如1.0.0-rc>
Enter description: <输入热更新版本描述>
Enter meta info: {"ok":1}
Ok.
Would you like to bind packages to this version?(Y/N)
```
此时版本已经提交到update服务但用户暂时看不到此更新你需要先将特定的原生包版本绑定到此热更新版本上。
此时输入Y立即绑定你也可以在将来使用`pushy update --platform <ios|android>`来使得对应原生包版本的用户更新。
除此以外,你还可以在网页端操作,简单的将对应的原生包版本拖到此热更新版本下即可。
```
Offset 0
1) FvXnROJ1 1.0.1 (no package)
2) FiWYm9lB 1.0 [1.0]
Enter versionId or page Up/page Down/Begin(U/D/B) <输入序号,U/D翻页,B回到开始序号就是上面列表中)前面的数字>
1) 1.0(normal) - 3 FiWYm9lB (未命名)
Total 1 packages.
Enter packageId: <输入原生包版本序号,序号就是上面列表中)前面的数字>
```
版本绑定完毕后,客户端就应当可以检查到更新并进行更新了。
恭喜你,至此为止,你已经完成了植入代码热更新的全部工作。接下来,你可以查阅[常见问题与高级指南](faq_advance.md)了解更多深入的知识,尤其是在实际项目中的运用技巧。

View File

@@ -1,25 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react-native-update - react-native hot update</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="react-native hot update">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'react-native-update',
repo: 'https://github.com/reactnativecn/react-native-pushy',
formatUpdated: '{MM}/{DD} {HH}:{mm}',
loadSidebar: true,
subMaxLevel: 2,
auto2top: true
}
</script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
</body>
</html>

View File

@@ -1 +1 @@
["update.reactnative.cn"] ["update.react-native.cn", "update.reactnative.cn"]

1
endpoints.json Normal file
View File

@@ -0,0 +1 @@
["https://update.react-native.cn/api", "https://update.reactnative.cn/api"]

View File

@@ -6,13 +6,11 @@
// Copyright © 2016 erica. All rights reserved. // Copyright © 2016 erica. All rights reserved.
// //
#if __has_include(<React/RCTBridge.h>)
#import <React/RCTBridgeModule.h> #import <React/RCTBridgeModule.h>
#else #import <React/RCTEventEmitter.h>
#import "RCTBridgeModule.h"
#endif
@interface RCTPushy : NSObject<RCTBridgeModule>
@interface RCTPushy : RCTEventEmitter<RCTBridgeModule>
+ (NSURL *)bundleURL; + (NSURL *)bundleURL;

View File

@@ -10,23 +10,19 @@
#import "RCTPushyDownloader.h" #import "RCTPushyDownloader.h"
#import "RCTPushyManager.h" #import "RCTPushyManager.h"
#if __has_include(<React/RCTBridge.h>)
#import "React/RCTEventDispatcher.h"
#import <React/RCTConvert.h> #import <React/RCTConvert.h>
#import <React/RCTLog.h> #import <React/RCTLog.h>
#else // #import <React/RCTReloadCommand.h>
#import "RCTEventDispatcher.h"
#import "RCTConvert.h"
#import "RCTLog.h"
#endif
//
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 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";
static NSString *const paramIsFirstLoadOk = @"isFirstLoadOK"; static NSString *const paramIsFirstLoadOk = @"isFirstLoadOK";
static NSString *const keyBlockUpdate = @"REACTNATIVECN_PUSHY_BLOCKUPDATE";
static NSString *const keyUuid = @"REACTNATIVECN_PUSHY_UUID";
static NSString *const keyFirstLoadMarked = @"REACTNATIVECN_PUSHY_FIRSTLOADMARKED_KEY"; static NSString *const keyFirstLoadMarked = @"REACTNATIVECN_PUSHY_FIRSTLOADMARKED_KEY";
static NSString *const keyRolledBackMarked = @"REACTNATIVECN_PUSHY_ROLLEDBACKMARKED_KEY"; static NSString *const keyRolledBackMarked = @"REACTNATIVECN_PUSHY_ROLLEDBACKMARKED_KEY";
static NSString *const KeyPackageUpdatedMarked = @"REACTNATIVECN_PUSHY_ISPACKAGEUPDATEDMARKED_KEY"; static NSString *const KeyPackageUpdatedMarked = @"REACTNATIVECN_PUSHY_ISPACKAGEUPDATEDMARKED_KEY";
@@ -47,8 +43,8 @@ static NSString * const ERROR_FILE_OPERATION = @"file operation error";
// event def // event def
static NSString * const EVENT_PROGRESS_DOWNLOAD = @"RCTPushyDownloadProgress"; static NSString * const EVENT_PROGRESS_DOWNLOAD = @"RCTPushyDownloadProgress";
static NSString * const EVENT_PROGRESS_UNZIP = @"RCTPushyUnzipProgress"; // static NSString * const EVENT_PROGRESS_UNZIP = @"RCTPushyUnzipProgress";
static NSString * const PARAM_PROGRESS_HASHNAME = @"hashname"; static NSString * const PARAM_PROGRESS_HASH = @"hash";
static NSString * const PARAM_PROGRESS_RECEIVED = @"received"; static NSString * const PARAM_PROGRESS_RECEIVED = @"received";
static NSString * const PARAM_PROGRESS_TOTAL = @"total"; static NSString * const PARAM_PROGRESS_TOTAL = @"total";
@@ -63,9 +59,9 @@ static BOOL ignoreRollback = false;
@implementation RCTPushy { @implementation RCTPushy {
RCTPushyManager *_fileManager; RCTPushyManager *_fileManager;
bool hasListeners;
} }
@synthesize bridge = _bridge;
@synthesize methodQueue = _methodQueue; @synthesize methodQueue = _methodQueue;
RCT_EXPORT_MODULE(RCTPushy); RCT_EXPORT_MODULE(RCTPushy);
@@ -88,31 +84,14 @@ RCT_EXPORT_MODULE(RCTPushy);
} }
else { else {
NSString *curVersion = pushyInfo[paramCurrentVersion]; NSString *curVersion = pushyInfo[paramCurrentVersion];
NSString *lastVersion = pushyInfo[paramLastVersion];
BOOL isFirstTime = [pushyInfo[paramIsFirstTime] boolValue]; BOOL isFirstTime = [pushyInfo[paramIsFirstTime] boolValue];
BOOL isFirstLoadOK = [pushyInfo[paramIsFirstLoadOk] boolValue]; BOOL isFirstLoadOK = [pushyInfo[paramIsFirstLoadOk] boolValue];
NSString *loadVersioin = curVersion; NSString *loadVersion = curVersion;
BOOL needRollback = (!ignoreRollback && isFirstTime == NO && isFirstLoadOK == NO) || loadVersioin.length<=0; BOOL needRollback = (!ignoreRollback && isFirstTime == NO && isFirstLoadOK == NO) || loadVersion.length<=0;
if (needRollback) { if (needRollback) {
loadVersioin = lastVersion; loadVersion = [self rollback];
if (lastVersion.length) {
// roll back to last version
[defaults setObject:@{paramCurrentVersion:lastVersion,
paramIsFirstTime:@(NO),
paramIsFirstLoadOk:@(YES),
paramPackageVersion:curPackageVersion}
forKey:keyPushyInfo];
}
else {
// roll back to bundle
[defaults setObject:nil forKey:keyPushyInfo];
}
[defaults setObject:@(YES) forKey:keyRolledBackMarked];
[defaults synchronize];
// ...need clear files later
} }
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.
@@ -125,13 +104,15 @@ RCT_EXPORT_MODULE(RCTPushy);
[defaults synchronize]; [defaults synchronize];
} }
if (loadVersioin.length) { NSString *downloadDir = [RCTPushy downloadDir];
NSString *downloadDir = [RCTPushy downloadDir]; while (loadVersion.length) {
NSString *bundlePath = [[downloadDir stringByAppendingPathComponent:loadVersion] stringByAppendingPathComponent:BUNDLE_FILE_NAME];
NSString *bundlePath = [[downloadDir stringByAppendingPathComponent:loadVersioin] stringByAppendingPathComponent:BUNDLE_FILE_NAME];
if ([[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:NULL]) { if ([[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:NULL]) {
NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath]; NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath];
return bundleURL; return bundleURL;
} else {
RCTLogError(@"RCTPushy -- bundle version %@ not found", loadVersion);
loadVersion = [self rollback];
} }
} }
} }
@@ -140,6 +121,29 @@ RCT_EXPORT_MODULE(RCTPushy);
return [RCTPushy binaryBundleURL]; return [RCTPushy binaryBundleURL];
} }
+ (NSString *) rollback {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
NSString *lastVersion = pushyInfo[paramLastVersion];
NSString *curPackageVersion = [RCTPushy packageVersion];
if (lastVersion.length) {
// roll back to last version
[defaults setObject:@{paramCurrentVersion:lastVersion,
paramIsFirstTime:@(NO),
paramIsFirstLoadOk:@(YES),
paramPackageVersion:curPackageVersion}
forKey:keyPushyInfo];
}
else {
// roll back to bundle
[defaults setObject:nil forKey:keyPushyInfo];
}
[defaults setObject:@(YES) forKey:keyRolledBackMarked];
[defaults synchronize];
return lastVersion;
}
+ (BOOL)requiresMainQueueSetup { + (BOOL)requiresMainQueueSetup {
// only set to YES if your module initialization relies on calling UIKit! // only set to YES if your module initialization relies on calling UIKit!
return NO; return NO;
@@ -155,6 +159,8 @@ RCT_EXPORT_MODULE(RCTPushy);
ret[@"buildTime"] = [RCTPushy buildTime]; ret[@"buildTime"] = [RCTPushy buildTime];
ret[@"isRolledBack"] = [defaults objectForKey:keyRolledBackMarked]; ret[@"isRolledBack"] = [defaults objectForKey:keyRolledBackMarked];
ret[@"isFirstTime"] = [defaults objectForKey:keyFirstLoadMarked]; ret[@"isFirstTime"] = [defaults objectForKey:keyFirstLoadMarked];
ret[@"blockUpdate"] = [defaults objectForKey:keyBlockUpdate];
ret[@"uuid"] = [defaults objectForKey:keyUuid];
NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo]; NSDictionary *pushyInfo = [defaults dictionaryForKey:keyPushyInfo];
ret[@"currentVersion"] = [pushyInfo objectForKey:paramCurrentVersion]; ret[@"currentVersion"] = [pushyInfo objectForKey:paramCurrentVersion];
@@ -188,6 +194,23 @@ RCT_EXPORT_MODULE(RCTPushy);
return self; return self;
} }
RCT_EXPORT_METHOD(setBlockUpdate:(NSDictionary *)options)
{
// NSMutableDictionary *blockUpdateInfo = [NSMutableDictionary new];
// blockUpdateInfo[@"reason"] = options[@"reason"];
// blockUpdateInfo[@"until"] = options[@"until"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:options forKey:keyBlockUpdate];
[defaults synchronize];
}
RCT_EXPORT_METHOD(setUuid:(NSString *)uuid)
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:uuid forKey:keyUuid];
[defaults synchronize];
}
RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary *)options RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) rejecter:(RCTPromiseRejectBlock)reject)
@@ -232,8 +255,11 @@ RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options) RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
{ {
NSString *hashName = options[@"hashName"]; NSString *hash = options[@"hash"];
if (hashName.length) { if (hash.length <= 0) {
hash = options[@"hashName"];
}
if (hash.length) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *lastVersion = nil; NSString *lastVersion = nil;
if ([defaults objectForKey:keyPushyInfo]) { if ([defaults objectForKey:keyPushyInfo]) {
@@ -242,7 +268,7 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
} }
NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] init]; NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] init];
newInfo[paramCurrentVersion] = hashName; newInfo[paramCurrentVersion] = hash;
newInfo[paramLastVersion] = lastVersion; newInfo[paramLastVersion] = lastVersion;
newInfo[paramIsFirstTime] = @(YES); newInfo[paramIsFirstTime] = @(YES);
newInfo[paramIsFirstLoadOk] = @(NO); newInfo[paramIsFirstLoadOk] = @(NO);
@@ -255,15 +281,21 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options) RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options)
{ {
NSString *hashName = options[@"hashName"]; NSString *hash = options[@"hash"];
if (hashName.length) { if (hash.length <= 0) {
hash = options[@"hashName"];
}
if (hash.length) {
[self setNeedUpdate:options]; [self setNeedUpdate:options];
// reload // reload 0.62+
dispatch_async(dispatch_get_main_queue(), ^{ // RCTReloadCommandSetBundleURL([[self class] bundleURL]);
[_bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"]; // RCTTriggerReloadCommandListeners(@"pushy reload");
[_bridge reload];
}); dispatch_async(dispatch_get_main_queue(), ^{
[self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
[self.bridge reload];
});
} }
} }
@@ -281,17 +313,43 @@ RCT_EXPORT_METHOD(markSuccess)
[self clearInvalidFiles]; [self clearInvalidFiles];
} }
#pragma mark - private #pragma mark - private
- (NSArray<NSString *> *)supportedEvents
{
return @[
EVENT_PROGRESS_DOWNLOAD,
// EVENT_PROGRESS_UNZIP
];
}
// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
- (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback - (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
{ {
NSString *updateUrl = [RCTConvert NSString:options[@"updateUrl"]]; NSString *updateUrl = [RCTConvert NSString:options[@"updateUrl"]];
NSString *hashName = [RCTConvert NSString:options[@"hashName"]]; NSString *hash = [RCTConvert NSString:options[@"hash"]];
if (updateUrl.length<=0 || hashName.length<=0) { if (hash.length <= 0) {
hash = [RCTConvert NSString:options[@"hashName"]];;
}
if (updateUrl.length <= 0 || hash.length <= 0) {
callback([self errorWithMessage:ERROR_OPTIONS]); callback([self errorWithMessage:ERROR_OPTIONS]);
return; return;
} }
NSString *originHashName = [RCTConvert NSString:options[@"originHashName"]]; NSString *originHash = [RCTConvert NSString:options[@"originHash"]];
if (type == PushyTypePatchFromPpk && originHashName<=0) { if (type == PushyTypePatchFromPpk && originHash <= 0) {
callback([self errorWithMessage:ERROR_OPTIONS]); callback([self errorWithMessage:ERROR_OPTIONS]);
return; return;
} }
@@ -302,35 +360,38 @@ RCT_EXPORT_METHOD(markSuccess)
callback([self errorWithMessage:ERROR_FILE_OPERATION]); callback([self errorWithMessage:ERROR_FILE_OPERATION]);
return; return;
} }
NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hashName, [self zipExtension:type]]]; NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hash, [self zipExtension:type]]];
NSString *unzipDir = [dir stringByAppendingPathComponent:hashName]; // NSString *unzipDir = [dir stringByAppendingPathComponent:hash];
RCTLogInfo(@"RCTPushy -- download file %@", updateUrl); RCTLogInfo(@"RCTPushy -- download file %@", updateUrl);
[RCTPushyDownloader download:updateUrl savePath:zipFilePath progressHandler:^(long long receivedBytes, long long totalBytes) { [RCTPushyDownloader download:updateUrl savePath:zipFilePath progressHandler:^(long long receivedBytes, long long totalBytes) {
[self.bridge.eventDispatcher sendAppEventWithName:EVENT_PROGRESS_DOWNLOAD if (self->hasListeners) {
body:@{ [self sendEventWithName:EVENT_PROGRESS_DOWNLOAD body:@{
PARAM_PROGRESS_HASHNAME:hashName, PARAM_PROGRESS_HASH:hash,
PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLongLong:receivedBytes], PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLongLong:receivedBytes],
PARAM_PROGRESS_TOTAL:[NSNumber numberWithLongLong:totalBytes] PARAM_PROGRESS_TOTAL:[NSNumber numberWithLongLong:totalBytes]
}]; }];
}
} completionHandler:^(NSString *path, NSError *error) { } completionHandler:^(NSString *path, NSError *error) {
if (error) { if (error) {
callback(error); callback(error);
} }
else { else {
RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath); RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath);
NSString *unzipFilePath = [dir stringByAppendingPathComponent:hashName]; NSString *unzipFilePath = [dir stringByAppendingPathComponent:hash];
[_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) { [self->_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) {
[self.bridge.eventDispatcher sendAppEventWithName:EVENT_PROGRESS_UNZIP // if (self->hasListeners) {
body:@{ // [self sendEventWithName:EVENT_PROGRESS_UNZIP
PARAM_PROGRESS_HASHNAME:hashName, // body:@{
PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber], // PARAM_PROGRESS_HASH:hash,
PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total] // PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber],
}]; // PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total]
// }];
// }
} completionHandler:^(NSString *path, BOOL succeeded, NSError *error) { } completionHandler:^(NSString *path, BOOL succeeded, NSError *error) {
dispatch_async(_methodQueue, ^{ dispatch_async(self->_methodQueue, ^{
if (error) { if (error) {
callback(error); callback(error);
} }
@@ -340,16 +401,16 @@ RCT_EXPORT_METHOD(markSuccess)
{ {
NSString *sourceOrigin = [[NSBundle mainBundle] resourcePath]; NSString *sourceOrigin = [[NSBundle mainBundle] resourcePath];
NSString *bundleOrigin = [[RCTPushy binaryBundleURL] path]; NSString *bundleOrigin = [[RCTPushy binaryBundleURL] path];
[self patch:hashName fromBundle:bundleOrigin source:sourceOrigin callback:callback]; [self patch:hash fromBundle:bundleOrigin source:sourceOrigin callback:callback];
} }
break; break;
case PushyTypePatchFromPpk: case PushyTypePatchFromPpk:
{ {
NSString *lastVertionDir = [dir stringByAppendingPathComponent:originHashName]; NSString *lastVersionDir = [dir stringByAppendingPathComponent:originHash];
NSString *sourceOrigin = lastVertionDir; NSString *sourceOrigin = lastVersionDir;
NSString *bundleOrigin = [lastVertionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME]; NSString *bundleOrigin = [lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
[self patch:hashName fromBundle:bundleOrigin source:sourceOrigin callback:callback]; [self patch:hash fromBundle:bundleOrigin source:sourceOrigin callback:callback];
} }
break; break;
default: default:
@@ -363,9 +424,9 @@ RCT_EXPORT_METHOD(markSuccess)
}]; }];
} }
- (void)patch:(NSString *)hashName 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
{ {
NSString *unzipDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hashName]; NSString *unzipDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
NSString *sourcePatch = [unzipDir stringByAppendingPathComponent:SOURCE_PATCH_NAME]; NSString *sourcePatch = [unzipDir stringByAppendingPathComponent:SOURCE_PATCH_NAME];
NSString *bundlePatch = [unzipDir stringByAppendingPathComponent:BUNDLE_PATCH_NAME]; NSString *bundlePatch = [unzipDir stringByAppendingPathComponent:BUNDLE_PATCH_NAME];
@@ -383,7 +444,7 @@ RCT_EXPORT_METHOD(markSuccess)
NSDictionary *copies = json[@"copies"]; NSDictionary *copies = json[@"copies"];
NSDictionary *deletes = json[@"deletes"]; NSDictionary *deletes = json[@"deletes"];
[_fileManager copyFiles:copies fromDir:sourceOrigin toDir:unzipDir deletes:deletes completionHandler:^(NSError *error) { [self->_fileManager copyFiles:copies fromDir:sourceOrigin toDir:unzipDir deletes:deletes completionHandler:^(NSError *error) {
if (error) { if (error) {
callback(error); callback(error);
} }

View File

@@ -99,16 +99,9 @@ completionHandler:(void (^)(NSError *error))completionHandler
// merge old files // merge old files
if (deletes!= nil) { if (deletes!= nil) {
NSError *error = nil;
NSString *srcDir = [fromDir stringByAppendingPathComponent:@"assets"]; NSString *srcDir = [fromDir stringByAppendingPathComponent:@"assets"];
NSString *desDir = [toDir stringByAppendingPathComponent:@"assets"]; NSString *desDir = [toDir stringByAppendingPathComponent:@"assets"];
[self _mergeContentsOfPath:srcDir intoPath:desDir deletes:deletes error:&error]; [self _mergeContentsOfPath:srcDir intoPath:desDir deletes:deletes];
if (error) {
if (completionHandler) {
completionHandler(error);
}
return;
}
} }
// copy files // copy files
@@ -126,10 +119,11 @@ completionHandler:(void (^)(NSError *error))completionHandler
NSError *error = nil; NSError *error = nil;
[fm copyItemAtPath:fromPath toPath:toPath error:&error]; [fm copyItemAtPath:fromPath toPath:toPath error:&error];
if (error) { if (error) {
if (completionHandler) { NSLog(@"Pushy copy error: %@", error.localizedDescription);
completionHandler(error); // if (completionHandler) {
} // completionHandler(error);
return; // }
// return;
} }
} }
if (completionHandler) { if (completionHandler) {
@@ -150,7 +144,7 @@ completionHandler:(void (^)(NSError *error))completionHandler
}); });
} }
- (void)_mergeContentsOfPath:(NSString *)srcDir intoPath:(NSString *)dstDir deletes:(NSDictionary *)deletes error:(NSError**)err - (void)_mergeContentsOfPath:(NSString *)srcDir intoPath:(NSString *)dstDir deletes:(NSDictionary *)deletes
{ {
NSFileManager *fm = [NSFileManager defaultManager]; NSFileManager *fm = [NSFileManager defaultManager];
NSDirectoryEnumerator *srcDirEnum = [fm enumeratorAtPath:srcDir]; NSDirectoryEnumerator *srcDirEnum = [fm enumeratorAtPath:srcDir];
@@ -159,7 +153,9 @@ completionHandler:(void (^)(NSError *error))completionHandler
NSString *srcFullPath = [srcDir stringByAppendingPathComponent:subPath]; NSString *srcFullPath = [srcDir stringByAppendingPathComponent:subPath];
NSString *potentialDstPath = [dstDir stringByAppendingPathComponent:subPath]; NSString *potentialDstPath = [dstDir stringByAppendingPathComponent:subPath];
NSError *error = nil;
BOOL inDeletes = NO; BOOL inDeletes = NO;
if (deletes) { if (deletes) {
NSString *path = [@"assets" stringByAppendingPathComponent:subPath]; NSString *path = [@"assets" stringByAppendingPathComponent:subPath];
@@ -171,18 +167,19 @@ completionHandler:(void (^)(NSError *error))completionHandler
BOOL isDirectory = ([fm fileExistsAtPath:srcFullPath isDirectory:&isDirectory] && isDirectory); BOOL isDirectory = ([fm fileExistsAtPath:srcFullPath isDirectory:&isDirectory] && isDirectory);
if (isDirectory) { if (isDirectory) {
if (![fm fileExistsAtPath:potentialDstPath isDirectory:nil]) { if (![fm fileExistsAtPath:potentialDstPath isDirectory:nil]) {
[fm createDirectoryAtPath:potentialDstPath withIntermediateDirectories:YES attributes:nil error:err]; [fm createDirectoryAtPath:potentialDstPath withIntermediateDirectories:YES attributes:nil error:&error];
if (err && *err) { if (error) {
return; NSLog(@"Pushy merge error: %@", error.localizedDescription);
// return;
} }
} }
} }
else { else {
if (![fm fileExistsAtPath:potentialDstPath]) { if (![fm fileExistsAtPath:potentialDstPath]) {
[fm copyItemAtPath:srcFullPath toPath:potentialDstPath error:err]; [fm copyItemAtPath:srcFullPath toPath:potentialDstPath error:&error];
if (err && *err) { if (error) {
return; NSLog(@"Pushy merge error: %@", error.localizedDescription);
// return;
} }
} }
} }

89
lib/endpoint.js Normal file
View File

@@ -0,0 +1,89 @@
let currentEndpoint = 'https://update.react-native.cn/api';
function ping(url, rejectImmediate) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = (e) => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
resolve(url);
} else {
rejectImmediate ? reject() : setTimeout(reject, 5000);
}
};
xhr.open('HEAD', url);
xhr.send();
xhr.timeout = 5000;
xhr.ontimeout = reject;
});
}
function logger(...args) {
// console.warn('pushy', ...args);
}
let backupEndpoints = [];
let backupEndpointsQueryUrl =
'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/endpoints.json';
export async function tryBackupEndpoints() {
if (!backupEndpoints.length && !backupEndpointsQueryUrl) {
return;
}
try {
await ping(getStatusUrl(), true);
logger('current endpoint ok');
return;
} catch (e) {
logger('current endpoint failed');
}
if (!backupEndpoints.length && backupEndpointsQueryUrl) {
try {
const resp = await fetch(backupEndpointsQueryUrl);
backupEndpoints = await resp.json();
logger('get remote endpoints:', backupEndpoints);
} catch (e) {
logger('get remote endpoints failed');
return;
}
}
await pickFatestAvailableEndpoint();
}
async function pickFatestAvailableEndpoint(endpoints = backupEndpoints) {
const fastestEndpoint = await Promise.race(
endpoints.map(pingAndReturnEndpoint),
);
if (typeof fastestEndpoint === 'string') {
logger(`pick endpoint: ${fastestEndpoint}`);
currentEndpoint = fastestEndpoint;
} else {
logger('all remote endpoints failed');
}
}
async function pingAndReturnEndpoint(endpoint = currentEndpoint) {
return ping(getStatusUrl(endpoint)).then(() => endpoint);
}
function getStatusUrl(endpoint = currentEndpoint) {
return `${endpoint}/status`;
}
export function getCheckUrl(APPKEY, endpoint = currentEndpoint) {
return `${endpoint}/checkUpdate/${APPKEY}`;
}
export function setCustomEndpoints({ main, backups, backupQueryUrl }) {
currentEndpoint = main;
backupEndpointsQueryUrl = null;
if (Array.isArray(backups) && backups.length > 0) {
backupEndpoints = backups;
pickFatestAvailableEndpoint();
}
if (typeof backupQueryUrl === 'string') {
backupEndpointsQueryUrl = backupQueryUrl;
}
}

View File

@@ -1,57 +0,0 @@
let availableDomain = 'update.react-native.cn';
function ping(domain, rejectImmediate) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = e => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
resolve(domain);
} else {
rejectImmediate ? reject() : setTimeout(reject, 5000);
}
};
xhr.open('HEAD', `https://${domain}`);
xhr.send();
xhr.timeout = 5000;
xhr.ontimeout = reject;
});
}
function logger(...args) {
// console.warn('pushy', ...args);
}
export async function tryBackupDomains() {
try {
await ping(availableDomain, true);
logger('main domain ok');
return;
} catch (e) {
logger('main domain failed');
}
let backupDomains = [];
try {
const resp = await fetch(
'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/domains.json',
);
backupDomains = await resp.json();
logger('get remote domains:', backupDomains);
} catch (e) {
logger('get remote domains failed');
return;
}
const fastestDomain = await Promise.race(backupDomains.map(ping));
if (typeof fastestDomain === 'string') {
logger(`pick domain: ${fastestDomain}`);
availableDomain = fastestDomain;
} else {
logger('all remote domains failed');
}
}
export default function getHost() {
return `https://${availableDomain}/api`;
}

48
lib/index.d.ts vendored
View File

@@ -5,32 +5,74 @@ export const isFirstTime: boolean;
export const isRolledBack: boolean; export const isRolledBack: boolean;
export interface ExpiredResult { export interface ExpiredResult {
upToDate?: false;
expired: true; expired: true;
downloadUrl: string; downloadUrl: string;
} }
export interface UpTodateResult { export interface UpTodateResult {
expired?: false;
upToDate: true; upToDate: true;
} }
export interface UpdateAvailableResult { export interface UpdateAvailableResult {
expired?: false;
upToDate?: false;
update: true; update: true;
name: string; // version name name: string; // version name
hash: string; hash: string;
description: string; description: string;
metaInfo: string; metaInfo: string;
pdiffUrl: string; pdiffUrl: string;
diffUrl: string; diffUrl?: string;
} }
export type CheckResult = Partial<ExpiredResult & UpTodateResult & UpdateAvailableResult>; export type CheckResult =
| ExpiredResult
| UpTodateResult
| UpdateAvailableResult;
export function checkUpdate(appkey: string): Promise<CheckResult>; export function checkUpdate(appkey: string): Promise<CheckResult>;
export function downloadUpdate(options: UpdateAvailableResult): Promise<undefined | string>; export function downloadUpdate(
info: UpdateAvailableResult,
eventListeners?: {
onDownloadProgress?: (data: ProgressData) => void;
},
): Promise<undefined | string>;
export function switchVersion(hash: string): void; export function switchVersion(hash: string): void;
export function switchVersionLater(hash: string): void; export function switchVersionLater(hash: string): void;
export function markSuccess(): void; export function markSuccess(): void;
export function downloadAndInstallApk({
url,
onDownloadProgress,
}: {
url: string;
onDownloadProgress?: (data: ProgressData) => void;
}): Promise<void>;
/**
* @param {string} main - The main api endpoint
* @param {string[]} [backups] - The back up endpoints.
* @param {string} [backupQueryUrl] - An url that return a json file containing an array of endpoint.
* like: ["https://backup.api/1", "https://backup.api/2"]
*/
export function setCustomEndpoints({
main,
backups,
backupQueryUrl,
}: {
main: string;
backups?: string[];
backupQueryUrl?: string;
}): void;
interface ProgressData {
hash: string;
received: number;
total: number;
}

View File

@@ -1,7 +1,20 @@
import getHost, { tryBackupDomains } from './getHost'; import {
import { NativeAppEventEmitter, NativeModules } from 'react-native'; tryBackupEndpoints,
getCheckUrl,
setCustomEndpoints,
} from './endpoint';
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
export { setCustomEndpoints };
const {
version: v,
} = require('react-native/Libraries/Core/ReactNativeVersion');
const RNVersion = `${v.major}.${v.minor}.${v.patch}`;
const Pushy = NativeModules.Pushy || {}; let Pushy = NativeModules.Pushy;
if (!Pushy) {
throw new Error('react-native-update模块无法加载请对照安装文档检查配置。');
}
export const downloadRootDir = Pushy.downloadRootDir; export const downloadRootDir = Pushy.downloadRootDir;
export const packageVersion = Pushy.packageVersion; export const packageVersion = Pushy.packageVersion;
@@ -9,10 +22,31 @@ export const currentVersion = Pushy.currentVersion;
export const isFirstTime = Pushy.isFirstTime; export const isFirstTime = Pushy.isFirstTime;
export const isRolledBack = Pushy.isRolledBack; export const isRolledBack = Pushy.isRolledBack;
export const buildTime = Pushy.buildTime; export const buildTime = Pushy.buildTime;
let blockUpdate = Pushy.blockUpdate;
let uuid = Pushy.uuid;
if (Platform.OS === 'android' && !Pushy.isUsingBundleUrl) {
throw new Error(
'react-native-update模块无法加载请对照文档检查Bundle URL的配置',
);
}
const eventEmitter = new NativeEventEmitter(Pushy);
if (!uuid) {
uuid = require('uuid/v4')();
Pushy.setUuid(uuid);
}
function logger(text) {
console.log(`Pushy: ${text}`);
}
logger('uuid: ' + uuid);
/* /*
Return json: Return json:
Package was expired: Package expired:
{ {
expired: true, expired: true,
downloadUrl: 'http://appstore/downloadUrl', downloadUrl: 'http://appstore/downloadUrl',
@@ -41,9 +75,20 @@ function assertRelease() {
export async function checkUpdate(APPKEY, isRetry) { export async function checkUpdate(APPKEY, isRetry) {
assertRelease(); assertRelease();
if (blockUpdate && blockUpdate.until > Date.now() / 1000) {
throw new Error(
`热更新已暂停,原因:${blockUpdate.reason}。请在"${new Date(
blockUpdate.until * 1000,
).toLocaleString()}"之后重试。`,
);
}
if (typeof APPKEY !== 'string') {
throw new Error('未检查到合法的APPKEY请查看update.json文件是否正确生成');
}
logger('checking update');
let resp; let resp;
try { try {
resp = await fetch(`${getHost()}/checkUpdate/${APPKEY}`, { resp = await fetch(getCheckUrl(APPKEY), {
method: 'POST', method: 'POST',
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
@@ -53,64 +98,113 @@ export async function checkUpdate(APPKEY, isRetry) {
packageVersion, packageVersion,
hash: currentVersion, hash: currentVersion,
buildTime, buildTime,
cInfo: {
pushy: require('../package.json').version,
rn: RNVersion,
os: Platform.OS + ' ' + Platform.Version,
uuid,
},
}), }),
}); });
} catch (e) { } catch (e) {
if (isRetry) { if (isRetry) {
throw new Error('Could not connect to pushy server'); throw new Error('Could not connect to pushy server');
} }
await tryBackupDomains(); await tryBackupEndpoints(APPKEY);
return checkUpdate(APPKEY, true); return checkUpdate(APPKEY, true);
} }
const result = await resp.json();
checkOperation(result.op);
if (resp.status !== 200) { if (resp.status !== 200) {
throw new Error((await resp.json()).message); throw new Error(result.message);
} }
return resp.json(); return result;
} }
export async function downloadUpdate(options) { function checkOperation(op) {
if (!Array.isArray(op)) {
return;
}
op.forEach((action) => {
if (action.type === 'block') {
blockUpdate = {
reason: action.reason,
until: (Date.now() + action.duration) / 1000,
};
Pushy.setBlockUpdate(blockUpdate);
}
});
}
export async function downloadUpdate(options, eventListeners) {
assertRelease(); assertRelease();
if (!options.update) { if (!options.update) {
return; return;
} }
let progressHandler;
if (eventListeners) {
if (eventListeners.onDownloadProgress) {
const downloadCallback = eventListeners.onDownloadProgress;
progressHandler = eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => {
if (progressData.hash === options.hash) {
downloadCallback(progressData);
}
});
}
}
if (options.diffUrl) { if (options.diffUrl) {
logger('downloading diff');
await Pushy.downloadPatchFromPpk({ await Pushy.downloadPatchFromPpk({
updateUrl: options.diffUrl, updateUrl: options.diffUrl,
hashName: options.hash, hash: options.hash,
originHashName: currentVersion, originHash: currentVersion,
}); });
} else if (options.pdiffUrl) { } else if (options.pdiffUrl) {
logger('downloading pdiff');
await Pushy.downloadPatchFromPackage({ await Pushy.downloadPatchFromPackage({
updateUrl: options.pdiffUrl, updateUrl: options.pdiffUrl,
hashName: options.hash, hash: options.hash,
});
} else {
await Pushy.downloadUpdate({
updateUrl: options.updateUrl,
hashName: options.hash,
}); });
} }
progressHandler && progressHandler.remove();
return options.hash; return options.hash;
} }
export function switchVersion(hash) { export function switchVersion(hash) {
assertRelease(); assertRelease();
Pushy.reloadUpdate({ hashName: hash }); logger('switchVersion');
Pushy.reloadUpdate({ hash });
} }
export function switchVersionLater(hash) { export function switchVersionLater(hash) {
assertRelease(); assertRelease();
Pushy.setNeedUpdate({ hashName: hash }); logger('switchVersionLater');
Pushy.setNeedUpdate({ hash });
} }
export function markSuccess() { export function markSuccess() {
assertRelease(); assertRelease();
logger('markSuccess');
Pushy.markSuccess(); Pushy.markSuccess();
} }
NativeAppEventEmitter.addListener('RCTPushyDownloadProgress', params => {}); export async function downloadAndInstallApk({ url, onDownloadProgress }) {
logger('downloadAndInstallApk');
NativeAppEventEmitter.addListener('RCTPushyUnzipProgress', params => {}); let hash = Date.now().toString();
let progressHandler;
if (onDownloadProgress) {
progressHandler = eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => {
if (progressData.hash === hash) {
onDownloadProgress(progressData);
}
});
}
await Pushy.downloadAndInstallApk({
url,
target: 'update.apk',
hash,
});
progressHandler && progressHandler.remove();
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-native-update", "name": "react-native-update",
"version": "5.5.7", "version": "5.10.0",
"description": "react-native hot update", "description": "react-native hot update",
"main": "lib/index.js", "main": "lib/index.js",
"scripts": { "scripts": {
@@ -26,5 +26,7 @@
"react-native": ">=0.27.0" "react-native": ">=0.27.0"
}, },
"homepage": "https://github.com/reactnativecn/react-native-pushy#readme", "homepage": "https://github.com/reactnativecn/react-native-pushy#readme",
"dependencies": {} "dependencies": {
"uuid": "3"
}
} }

View File

@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
s.vendored_libraries = 'RCTPushy/libRCTPushy.a' s.vendored_libraries = 'RCTPushy/libRCTPushy.a'
s.pod_target_xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"$(SRCROOT)/../node_modules/react-native-update/ios"' } s.pod_target_xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"$(SRCROOT)/../node_modules/react-native-update/ios"' }
s.resource = 'ios/pushy_build_time.txt' s.resource = 'ios/pushy_build_time.txt'
s.script_phase = { :name => 'Generate build time', :script => '"$(SRCROOT)/../node_modules/react-native-update/scripts/generateiOSBuildTime.sh"', :execution_position => :before_compile } s.script_phase = { :name => 'Generate build time', :script => 'set -x;date +%s > ${PODS_ROOT}/../../node_modules/react-native-update/ios/pushy_build_time.txt', :execution_position => :before_compile }
s.dependency 'React' s.dependency 'React'
s.dependency 'SSZipArchive' s.dependency 'SSZipArchive'

View File

@@ -1,5 +0,0 @@
#!/bin/bash
set -x
DEST="../../node_modules/react-native-update/ios"
date +%s > "$DEST/pushy_build_time.txt"

2593
yarn.lock

File diff suppressed because it is too large Load Diff