Commit 5b99ac67 authored by shiyunjie's avatar shiyunjie

热更新

parent 1b3257ee
......@@ -164,6 +164,7 @@ dependencies {
implementation project(':react-native-device-info')
implementation project(':react-native-spring-scrollview')
implementation project(':react-native-vector-icons')
implementation project(':agera-app-hotupdate')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation "com.facebook.react:react-native:+" // From node_modules
......
......@@ -21,10 +21,17 @@ import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
import cn.reactnative.modules.update.UpdateContext;
import cn.reactnative.modules.update.UpdatePackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(MainApplication.this);
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
......@@ -42,7 +49,8 @@ public class MainApplication extends Application implements ReactApplication {
new LinearGradientPackage(),
new RNDeviceInfo(),
new SpringScrollViewPackage(),
new VectorIconsPackage()
new VectorIconsPackage(),
new UpdatePackage()
);
}
......
......@@ -19,5 +19,7 @@ include ':react-native-spring-scrollview'
project(':react-native-spring-scrollview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spring-scrollview/android')
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':agera-app-hotupdate'
project(':agera-app-hotupdate').projectDir = new File(rootProject.projectDir, '../node_modules/agera-app-hotupdate/android')
include ':app'
......@@ -55,8 +55,11 @@
6068B983236A42738266D0CE /* libLottie.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD923ED2B8C4C44B328B1B0 /* libLottie.a */; };
7D086754CFF647B296C82959 /* FontAwesome5_Brands.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8BEF1FB779D54460BAA6C75D /* FontAwesome5_Brands.ttf */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
833F812222F17BF100111462 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 833F812122F17BF100111462 /* libz.tbd */; };
833F812422F17C3C00111462 /* libbz2.1.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 833F812322F17C3C00111462 /* libbz2.1.0.tbd */; };
83CA52CD22D8EFD0005440C0 /* Lottie.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 836D007C22C6345500DC9A54 /* Lottie.framework */; };
83CA52CE22D8EFD0005440C0 /* Lottie.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 836D007C22C6345500DC9A54 /* Lottie.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
83DD9C1B22F295E5008CB4B0 /* libRCTHotUpdate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83DD9C1A22F295CE008CB4B0 /* libRCTHotUpdate.a */; };
83FA0E6422CAE564000CDF1B /* libART.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83FA0E2A22CAE546000CDF1B /* libART.a */; };
97D73CDBCBBF483C99E06DBA /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A45B683174C84617B17BFEB8 /* FontAwesome.ttf */; };
9BD4B34961424375BF4F1F92 /* libRNGestureHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F86DBC4936427193CB045A /* libRNGestureHandler.a */; };
......@@ -462,6 +465,13 @@
remoteGlobalIDString = 62CA59B71E3C173B002D7188;
remoteInfo = Lottie_iOS;
};
83DD9C1922F295CE008CB4B0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83DD9C1522F295CE008CB4B0 /* RCTHotUpdate.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 91C5EFFF1C76ECA90037E727;
remoteInfo = RCTHotUpdate;
};
83F2776D22B25E860066BA73 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DC7A0D31E6A74DA6B87DABB7 /* RNDeviceInfo.xcodeproj */;
......@@ -581,6 +591,9 @@
8052B4491B5547D9A29FFF0E /* FastImage.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = FastImage.xcodeproj; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = "<group>"; };
8152F9826A9C45E1985E1CB9 /* libLottieReactNative.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libLottieReactNative.a; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
833F812122F17BF100111462 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
833F812322F17C3C00111462 /* libbz2.1.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.1.0.tbd; path = usr/lib/libbz2.1.0.tbd; sourceTree = SDKROOT; };
83DD9C1522F295CE008CB4B0 /* RCTHotUpdate.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTHotUpdate.xcodeproj; path = "../node_modules/agera-app-hotupdate/ios/RCTHotUpdate.xcodeproj"; sourceTree = "<group>"; };
83FA0E2422CAE546000CDF1B /* ART.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ART.xcodeproj; path = "../node_modules/react-native/Libraries/ART/ART.xcodeproj"; sourceTree = "<group>"; };
8A01206684554F25837ADFFE /* FontAwesome5_Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Regular.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf"; sourceTree = "<group>"; };
8BB06A9FC75847828D9E5BE1 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
......@@ -621,6 +634,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
833F812422F17C3C00111462 /* libbz2.1.0.tbd in Frameworks */,
833F812222F17BF100111462 /* libz.tbd in Frameworks */,
ED297163215061F000B7C4FE /* JavaScriptCore.framework in Frameworks */,
ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */,
11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */,
......@@ -647,6 +662,7 @@
F568EBF96A8C4A40B9DEE25F /* libRNSVG.a in Frameworks */,
506F0BD652134D5485198568 /* libRNCAsyncStorage.a in Frameworks */,
3AC42A78256D417BACE0E7D9 /* libRNReanimated.a in Frameworks */,
83DD9C1B22F295E5008CB4B0 /* libRCTHotUpdate.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -800,6 +816,8 @@
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
833F812322F17C3C00111462 /* libbz2.1.0.tbd */,
833F812122F17BF100111462 /* libz.tbd */,
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
2D16E6891FA4F8E400B85C8A /* libReact.a */,
......@@ -836,6 +854,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
83DD9C1522F295CE008CB4B0 /* RCTHotUpdate.xcodeproj */,
83FA0E2422CAE546000CDF1B /* ART.xcodeproj */,
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
146833FF1AC3E56700842450 /* React.xcodeproj */,
......@@ -996,6 +1015,14 @@
name = Products;
sourceTree = "<group>";
};
83DD9C1622F295CE008CB4B0 /* Products */ = {
isa = PBXGroup;
children = (
83DD9C1A22F295CE008CB4B0 /* libRCTHotUpdate.a */,
);
name = Products;
sourceTree = "<group>";
};
83F2776922B25E860066BA73 /* Products */ = {
isa = PBXGroup;
children = (
......@@ -1208,6 +1235,10 @@
ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
},
{
ProductGroup = 83DD9C1622F295CE008CB4B0 /* Products */;
ProjectRef = 83DD9C1522F295CE008CB4B0 /* RCTHotUpdate.xcodeproj */;
},
{
ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
},
......@@ -1643,6 +1674,13 @@
remoteRef = 83BE6C3822C859DB00366C0C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83DD9C1A22F295CE008CB4B0 /* libRCTHotUpdate.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTHotUpdate.a;
remoteRef = 83DD9C1922F295CE008CB4B0 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83F2776E22B25E860066BA73 /* libRNDeviceInfo.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
......@@ -1961,6 +1999,7 @@
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
"$(SRCROOT)/../node_modules/react-native-reanimated/ios/**",
"$(SRCROOT)/../node_modules/agera-app-hotupdate/ios",
);
INFOPLIST_FILE = BasicApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......@@ -1971,7 +2010,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.cntaiping.tpapptest;
PRODUCT_NAME = BasicApp;
PROVISIONING_PROFILE_SPECIFIER = tpapptestDep20181207;
PROVISIONING_PROFILE_SPECIFIER = "tpappDevelopment2018-7-26";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
......@@ -1998,6 +2037,7 @@
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
"$(SRCROOT)/../node_modules/react-native-reanimated/ios/**",
"$(SRCROOT)/../node_modules/agera-app-hotupdate/ios",
);
INFOPLIST_FILE = BasicApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......@@ -2008,7 +2048,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.cntaiping.tpapptest;
PRODUCT_NAME = BasicApp;
PROVISIONING_PROFILE_SPECIFIER = tpapptestADHoc20181207;
PROVISIONING_PROFILE_SPECIFIER = tpapptestADHoc2018913;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
......
......@@ -10,6 +10,7 @@
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <RCTHotUpdate/RCTHotUpdate.h>
@implementation AppDelegate
......@@ -35,8 +36,16 @@
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
// 非DEBUG情况下替换为热更新bundle
return [RCTHotUpdate bundleURL];
#endif
}
//{
//#if DEBUG
// return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
//#else
// return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
//#endif
//}
@end
......@@ -30,6 +30,11 @@
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>172.20.10.5:3333</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
......
......@@ -2746,6 +2746,61 @@
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz",
"integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw=="
},
"agera-app-hotupdate": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/agera-app-hotupdate/-/agera-app-hotupdate-0.0.3.tgz",
"integrity": "sha512-zetwOlkyk2BnBOkXtGH21LkxoYZCWO4UWK+uR49WpmmG5ciWDR/Bm2rqAjnhWMsSO64EsHZLdWocWeSo5NDYIg==",
"requires": {
"cli-arguments": "^0.2.1",
"decompress-zip": "^0.3.1",
"fs-promise": "^0.4.1",
"glob": "^7.1.2",
"ipa-metadata": "^1.4.0",
"isomorphic-fetch": "^2.2.1",
"mkdir-recursive": "^0.2.1",
"node-apk-parser": "^0.2.3",
"progress": "^1.1.8",
"read": "^1.0.7",
"request": "^2.69.0",
"rimraf": "^2.5.2",
"simple-plist": "^0.3.0",
"temporary": "^0.0.8",
"yauzl": "2.4.1",
"yazl": "2.3.0"
},
"dependencies": {
"base64-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
"integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE="
},
"plist": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
"integrity": "sha1-V8zbeggh3yGDEhejytVOPhRqECU=",
"requires": {
"base64-js": "1.2.0",
"xmlbuilder": "8.2.2",
"xmldom": "0.1.x"
}
},
"simple-plist": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-0.3.0.tgz",
"integrity": "sha512-zHzV7TxUsVzHv8Nt+eStifDNCNIOuS92POdFf/5MHAxtWA7IASzVawCasxNIT4bn5IfrrnMB1eXpagJMLWbG5w==",
"requires": {
"bplist-creator": "0.0.7",
"bplist-parser": "0.1.1",
"plist": "2.1.0"
}
},
"xmlbuilder": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
"integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M="
}
}
},
"ajv": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
......@@ -11561,6 +11616,14 @@
"react-native-animatable": "^1.3.1"
}
},
"react-native-progress": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/react-native-progress/-/react-native-progress-3.6.0.tgz",
"integrity": "sha512-zzTe595xaaskyfR5OzaGrU4O0R+YkgdEw+EspgGD7wh8Hu0fs6ue3xLW+HEbTjOCn62pCRivwi3NxbpWNBCC7Q==",
"requires": {
"prop-types": "^15.7.2"
}
},
"react-native-ratings": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-6.3.1.tgz",
......@@ -11657,61 +11720,6 @@
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.7.1.tgz",
"integrity": "sha512-GdKrosksYeDd1VRjb8PSSloY2l5MrNpRHAVxald4p1eiKkvonl7TJ1TN6FeA1wtsy/9x8CJ0dSIWlV/Xyq9R9g=="
},
"react-native-update-mutlirn-hg": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/react-native-update-mutlirn-hg/-/react-native-update-mutlirn-hg-3.1.1.tgz",
"integrity": "sha512-q7u2XTGzGBdjB8fwZlZOeuoO0617Iw4AsTyCFZKRXPIAmkqDU9c2QCwfkd9BFK8t+Ys+oCdRpZkMTjZRZxBM6w==",
"requires": {
"cli-arguments": "^0.2.1",
"decompress-zip": "^0.3.1",
"fs-promise": "^0.4.1",
"glob": "^7.1.2",
"ipa-metadata": "^1.4.0",
"isomorphic-fetch": "^2.2.1",
"mkdir-recursive": "^0.2.1",
"node-apk-parser": "^0.2.3",
"progress": "^1.1.8",
"read": "^1.0.7",
"request": "^2.69.0",
"rimraf": "^2.5.2",
"simple-plist": "^0.3.0",
"temporary": "^0.0.8",
"yauzl": "2.4.1",
"yazl": "2.3.0"
},
"dependencies": {
"base64-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
"integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE="
},
"plist": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
"integrity": "sha1-V8zbeggh3yGDEhejytVOPhRqECU=",
"requires": {
"base64-js": "1.2.0",
"xmlbuilder": "8.2.2",
"xmldom": "0.1.x"
}
},
"simple-plist": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-0.3.0.tgz",
"integrity": "sha512-zHzV7TxUsVzHv8Nt+eStifDNCNIOuS92POdFf/5MHAxtWA7IASzVawCasxNIT4bn5IfrrnMB1eXpagJMLWbG5w==",
"requires": {
"bplist-creator": "0.0.7",
"bplist-parser": "0.1.1",
"plist": "2.1.0"
}
},
"xmlbuilder": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
"integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M="
}
}
},
"react-native-vector-icons": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-6.6.0.tgz",
......
var hello = require('./node_modules/react-native-update-mutlirn-hg/local-cli')
var hello = require('./node_modules/Agera-App-HotUpdate/local-cli')
hello.run()
......@@ -10,6 +10,7 @@
},
"dependencies": {
"@react-native-community/async-storage": "^1.5.0",
"agera-app-hotupdate": "0.0.3",
"axios": "^0.18.0",
"lodash": "^4.17.11",
"lottie-react-native": "^2.6.1",
......@@ -24,6 +25,7 @@
"react-native-largelist-v3": "^3.0.14",
"react-native-linear-gradient": "^2.5.4",
"react-native-modal": "^11.1.0",
"react-native-progress": "^3.6.0",
"react-native-reanimated": "^1.1.0",
"react-native-root-toast": "^3.1.2",
"react-native-spring-scrollview": "^2.0.22",
......@@ -31,7 +33,6 @@
"react-native-svg": "^9.5.1",
"react-native-swiper": "^1.5.14",
"react-native-tab-view": "2.7.1",
"react-native-update-mutlirn-hg": "^3.1.1",
"react-native-vector-icons": "^6.4.2",
"react-navigation": "^3.11.0",
"react-navigation-redux-helpers": "^3.0.2",
......
......@@ -34,6 +34,7 @@ import ProductDetailPage from '../pages/insurePage/ProductDetailPage';
import FillPolicyInfoPage from '../pages/insurePage/FillPolicyInfoPage';
import PaymentPage from '../pages/insurePage/PaymentPage';
import PolicyResultPage from '../pages/insurePage/PolicyResultPage';
import HotUpdatePage from '../pages/HotUpdateDemo';
import { initialRouteName, RootPageInitialName } from '../utils/constants';
import { TabOptions } from '../components/TabOptions';
......@@ -154,6 +155,9 @@ const navigator = createStackNavigator({
PolicyResultPage: {
screen: PolicyResultPage,
},
HotUpdatePage: {
screen: HotUpdatePage,
},
}, {
initialRouteName,
mode: 'card',
......
......@@ -3,21 +3,27 @@
*/
import React, { Component } from 'react';
import { AppState, Text, SafeAreaView, BackHandler, ToastAndroid } from 'react-native';
import { Provider } from 'react-redux';
import {
AppState, Text, SafeAreaView, BackHandler, ToastAndroid,
} from 'react-native';
import { connect, Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/es/integration/react';
import configureStore from './basicStore';
import BasicNavigator from './BasicNavigator';
import StyleSheet from './utils/StyleSheet';
import { pop } from './BasicNavigator/actions';
import HotUpdateLoading from './components/HotUpdate/HotUpdateLoading';
const styles = StyleSheet.create({
container: {
flex: 1,
},
})
});
const { store, persistor } = configureStore();
const { store, persistor } = configureStore()
class MainApp extends Component {
componentDidMount() {
......@@ -40,14 +46,14 @@ class MainApp extends Component {
//console.log('handleAppChange:')
if (currentAppState === 'active') {
//checkForUpdate(true)
console.log('handleAppChange','active');
console.log('handleAppChange', 'active');
}
}
onBackPress = () => {
console.log('onBackPress');
//这里的路由信息是你自己项目中的,通过这个原理,我们还是可以提示一些其他信息,比如表单没填写完整等等
const state = store.getState()
const state = store.getState();
if (state.nav.routes.length <= 1) {
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
......@@ -69,6 +75,7 @@ class MainApp extends Component {
<PersistGate loading={<Text>MyLoading...</Text>} persistor={persistor}>
<SafeAreaView style={styles.container}>
<BasicNavigator param={this.props} />
<HotUpdateLoading />
</SafeAreaView>
</PersistGate>
</Provider>
......
......@@ -16,7 +16,7 @@ import {
} from 'react-navigation-redux-helpers';
import middleWare from './utils/middleware';
import { markUpdateSuccess } from './utils/update';
import { markUpdateSuccess } from './components/HotUpdate/update';
import AppReducer from './reducers';
......
......@@ -49,7 +49,7 @@ export function HomeHeader(props) {
fontSize: 14,
}}
>
{'搜索"保险服务"'}
{'搜索"保险服务"热更新前'}
</Text>
</View>
<View style={{
......
/**
* @flow
*/
import React, { Component } from 'react';
import { Circle } from 'react-native-progress';
import {
View,
Text,
Platform,
Dimensions,
StyleSheet,
NativeAppEventEmitter,
} from 'react-native';
import Button from '../ThemeButton';
const { width: deviceWidth } = Dimensions.get('window');
type Props = {
progress : number,
reloadUpdate: () => void,
downloadUpdate: () => void,
setShowDialog: () => void,
}
type State = {
progress: number,
}
// const isLessLollipop = Platform.OS === 'android' && Platform.Version < 21
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
paddingTop: Platform.OS === 'ios' ? 64 : 44,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
buttonTextColor: {
color: '#2E75C5',
fontSize: 16,
},
mainButton: {
width: Number(deviceWidth - 60),
marginTop: 5,
backgroundColor: '#fff',
marginBottom: 5,
},
});
class DownloadModal extends Component {
constructor(props:Props) {
super(props);
this.state = {
progress: props.progress || -1,
};
}
state:State
componentWillReceiveProps(nextProps: Object) {
const { progress } = nextProps;
// console.log('componentWillReceiveProps', progress)
if (progress !== this.state.progress) {
this.setState({ progress });
}
}
renderButton = (state, prop) => {
if (state.progress === 2) {
return (
<View
style={{
width: Number(deviceWidth - 60),
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderTopColor: '#c9c9c9',
borderTopWidth: StyleSheet.hairlineWidth,
}}
>
<Button
titleStyle={[styles.buttonTextColor]}
buttonStyle={{
backgroundColor: '#fff',
}}
containerStyle={{ flex: 1 }}
title="退出"
onPress={() => {
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: -2,
total: 1,
});
}}
/>
<View
style={{
width: StyleSheet.hairlineWidth,
height: 50,
backgroundColor: '#c9c9c9',
}}
/>
<Button
titleStyle={[styles.buttonTextColor]}
buttonStyle={{
backgroundColor: '#fff',
}}
containerStyle={{ flex: 1 }}
title="开始下载"
onPress={() => {
prop.downloadUpdate();
}}
/>
</View>
);
} if (state.progress === 10) {
return (
<Button
titleStyle={styles.buttonTextColor}
buttonStyle={styles.mainButton}
title="重启"
onPress={() => {
prop.setShowDialog();
setTimeout(() => prop.reloadUpdate());
}}
/>
);
}
return (
<Button
titleStyle={styles.buttonTextColor}
buttonStyle={styles.mainButton}
title="退出"
onPress={() => {
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: -2,
total: 1,
});
}}
/>
);
}
render() {
let title = '正在下载资源,请稍后...';
if (this.state.progress === 2) {
title = '发现新资源,要下载吗?';
} else if (this.state.progress === 10) {
title = '已完成下载, 需要重启应用';
} else if (this.state.progress === -1) {
title = '下载失败,请稍后再试...';
}
return (
<View style={styles.container}>
<View
style={{
width: Number(deviceWidth - 60),
backgroundColor: 'white',
alignItems: 'center',
borderRadius: 10,
}}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}
>
{ this.state.progress !== -1 && this.state.progress !== 2
? (
<Circle
style={{ margin: 10 }}
size={50}
direction="clockwise" // 逆时针 顺时针,默认顺时针
progress={this.state.progress}
showsText
textStyle={{ fontSize: 14 }}
indeterminate={false}
/>
) : <View style={{ height: 70 }} />
}
<Text
style={{
marginTop: 10,
paddingBottom: 10,
fontSize: 16,
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
//borderBottomColor: '#c9c9c9',
//borderBottomWidth: StyleSheet.hairlineWidth,
}}
>
{ title }
</Text>
</View>
<View
style={{
height: 1 / 3,
width: Number(deviceWidth - 60),
backgroundColor: '#c9c9c9',
}}
/>
{this.renderButton(this.state, this.props)}
</View>
</View>
);
}
}
export default DownloadModal;
/**
* @flow
*/
import React, { Component, Element } from 'react';
import { connect } from 'react-redux';
import {
TouchableOpacity,
View,
StatusBar,
ScrollView,
Dimensions,
StyleSheet,
Platform,
NativeModules,
BackAndroid,
NativeAppEventEmitter,
} from 'react-native';
import { compose } from 'redux';
import DownloadModal from './DownloadModal';
import { reloadUpdate, downloadUpdate, } from './update';
import hotUpdate from './action';
const styles = StyleSheet.create({
container: {
flex: 1,
position: 'absolute',
bottom: 0,
top: 0,
left: 0,
right: 0,
},
});
type PropsType = {
progress: number,
showDialog: boolean,
path: string,
hash: string,
setShowDialog: ()=>{},
progressEdit: ()=>{},
setPath: ()=>{},
setHash: ()=>{},
}
class HotUpdateLoading extends Component {
constructor(props:PropsType) {
super(props);
this.downloadListener = null;
}
componentDidMount() {
const {
setShowDialog,
progressEdit,
setPath,
setHash,
} = this.props;
this.downloadListener = NativeAppEventEmitter.addListener(
'RCTHotUpdateDownloadProgress', (e) => {
console.log('DownloadProgress:', e);
const progress = Number(e.received) / Number(e.total);
if (progress === 2) {
setShowDialog(true);
setPath(e.path);
setHash(e.hash);
progressEdit(progress);
} else if (progress === -2) {
// 取消热更新更新
setShowDialog(false);
progressEdit(progress);
setPath('');
setHash('');
// 退出APP
//if (Platform.OS === 'ios') {
// NativeModules.RNExitApp.exitApp()
//} else {
// BackAndroid.exitApp()
//}
} else if (progress === -1) {
progressEdit(progress);
} else if (progress === 10) {
setHash(e.hash);
progressEdit(progress);
} else {
const num = Number(progress.toFixed(2));
progressEdit(num);
}
},
);
}
componentWillUnmount() {
if (this.downloadListener) {
this.downloadListener.remove();
}
}
render() {
const {
showDialog, hash, path,
progress, setShowDialog,
progressEdit, setPath, setHash,
} = this.props;
return (
showDialog
? (
<View style={styles.container}>
<DownloadModal
style={{ flex: 1 }}
progress={progress}
reloadUpdate={() => reloadUpdate(hash, true)}
downloadUpdate={() => downloadUpdate(path, true, hash)}
setShowDialog={() => {
setShowDialog(false);
setPath('');
setHash('');
progressEdit(-2);
}}
/>
</View>
) : null
);
}
}
function propsMapping({ hotUpdateLoading }) {
return {
...hotUpdateLoading,
};
}
function actionMapping(dispatch) {
return {
setShowDialog: compose(dispatch, hotUpdate.showDialog),
progressEdit: compose(dispatch, hotUpdate.progressEdit),
setPath: compose(dispatch, hotUpdate.setPath),
setHash: compose(dispatch, hotUpdate.setHash),
};
}
export default connect(propsMapping, actionMapping)(HotUpdateLoading);
/**
* @flow
*/
function progressEdit(payload: number) {
return {
type: 'hotUpdateLoading/progress',
payload,
}
}
function showDialog(payload: boolean) {
return {
type: 'hotUpdateLoading/showDialog',
payload,
};
}
function setPath(payload: string) {
return {
type: 'hotUpdateLoading/path',
payload,
};
}
function setHash(payload: string) {
return {
type: 'hotUpdateLoading/hash',
payload,
};
}
export default {
progressEdit,
showDialog,
setPath,
setHash,
};
/**
* @flow
*/
import { combineReducers } from 'redux';
type Reducer<S, A> = (state: S, action: A) => S
type PayloadAction<P> = {
type: string,
payload: P,
}
type ReplaceReducer<T> = Reducer<T, PayloadAction<T>>
function replaceReducer<T>(actionType: string, defaultValue: T): ReplaceReducer<T> {
return (state = defaultValue, action) => {
if (action.type === actionType) {
return action.payload;
}
return state;
};
}
const progress = replaceReducer('hotUpdateLoading/progress', -2)
const showDialog = replaceReducer('hotUpdateLoading/showDialog', false)
const path = replaceReducer('hotUpdateLoading/path', '')
const hash = replaceReducer('hotUpdateLoading/hash', '')
export default combineReducers({
progress,
showDialog,
path,
hash,
});
/**
* @flow
*/
import {
Platform, Linking, NativeAppEventEmitter, NativeModules,
} from 'react-native';
import { packageVersion, currentVersion } from 'agera-app-hotupdate';
const { HotUpdate } = NativeModules;
/*
{
"ios": {
"binary": "2.6.6",
"url": "http://www.baidu.com",
"patch": "http://127.0.0.1:8080/ios_2_6_7.ppk"
},
"android": {
"binary": "1.6.2",
"url": "http://www.baidu.com"
"patch": "http://127.0.0.1:8080/android_2_6_7.ppk"
}
}
*/
/*const downloadUpdateInfo = async () => {
// const response = await fetch(updateInfoURL(APIDeps.deviceInfo.env || 'DEV'))
const response = await fetch(updateInfoURL(ENV))
const updatePayload = await response.json()
const platformPPK = updatePayload[Platform.OS] || {}
APIDeps.ppkPath = platformPPK.patch
return platformPPK
}*/
const downloadAndInstall = async (url, interactive, hash) => {
console.log('downloadAndInstall_hash:',hash)
const result = await HotUpdate.downloadUpdate({
updateUrl: url,
hashName: hash,
});
console.log('downloadAndInstall', result)
if (!result) {
// await HotUpdate.reloadUpdate({ hashName: hash })
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: 10,
total: 1,
hash,
});
if (interactive) {
// Alert.alert('资源更新成功', null)
}
} else if (interactive) {
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: -1,
total: 1,
});
// Alert.alert('下载失败,请稍后再试...', null)
}
};
export async function downloadUpdate(url:string, interactive:boolean, hash:string) {
await downloadAndInstall(url, interactive, hash);
}
export async function reloadUpdate(hash:string, interactive:boolean) {
await HotUpdate.reloadUpdate({ hashName: hash });
if (interactive) {
// Alert.alert('资源更新成功', hash, null)
}
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: -2,
total: 1,
});
if (Platform.OS === 'android') {
//HybridDevice.restartApp()
}
}
// function asyncAlert(message) {
// return new Promise(success => {
// Alert.alert(message, null, [{ text: '确定', onPress: success }])
// })
// }
export function markUpdateSuccess() {
HotUpdate.markSuccess();
}
/*export async function checkBinaryVersionAction() {
const updateInfo = await downloadUpdateInfo()
const { binary, url } = updateInfo || {}
if (versionCheck(packageVersion, binary) && url) {
if (Platform.OS === 'android') {
HybridDevice.updateSysVersion(url)
} else {
Alert.alert('版本更新', '发现新版本', [{
text: '更新',
onPress: () => HybridDevice.updateSysVersion(url),
}])
}
} else {
Alert.alert('版本已是最新')
}
return []
}*/
export default async function (interactive: boolean = false) {
if (__DEV__) {
return;
}
//const updateInfo = await downloadUpdateInfo()
if (interactive) {
// await asyncAlert(JSON.stringify({
// packageVersion,
// currentVersion,
// updateInfo,
// }))
}
//
//const { binary, url, patch } = updateInfo || {}
//
//
//const result = versionCheck(packageVersion, binary)
//
//if (result === GREATER_THEN) {
// return
//}
//
//if (result === LESS_THEN && url) {
// // if (Platform.OS === 'android') {
// // HybridDevice.updateSysVersion(url)
// // } else {
// Alert.alert('版本更新', '发现新版本啦', [{
// text: '更新',
// onPress: () => Linking.openURL(url),
// }])
// // }
// return
//}
//if (result === EQUAL && patch && (currentVersion !== md5(patch))) {
// if (interactive) {
// await asyncAlert('发现新的系统资源,请更新......')
// }
// await downloadAndInstall(patch, interactive)
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: 2,
total: 1,
path: '',
});
//}
}
......@@ -10,8 +10,8 @@ type Props = {
width: number
}
function SwiperBanner(props:Props) {
//console.log('SwiperBanner',props)
function SwipeBanner(props:Props) {
//console.log('SwipeBanner',props)
return (
<SwipeView
showsButtons={false}
......@@ -19,7 +19,7 @@ function SwiperBanner(props:Props) {
height={props.height}
width={props.width}
autoplayTimeout={5}
paginationStyle={{ bottom: 0 }}
paginationStyle={{ bottom: 10 }}
>
{
props.children
......@@ -28,4 +28,4 @@ function SwiperBanner(props:Props) {
);
}
export default SwiperBanner;
export default SwipeBanner;
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/
import React, { Component } from 'react';
import {
StyleSheet,
View,
RefreshControl,
TouchableOpacity,
NativeAppEventEmitter,
} from 'react-native';
import { connect } from 'react-redux';
import { compose } from 'redux';
import Text from '../../components/Text';
import Button from '../../components/ThemeButton';
import TextInput from '../../components/TextInput';
import NavigationBar from '../../components/NavigationBar';
import BackButton from '../../components/BackButton';
import { push, pop } from '../../BasicNavigator/actions';
import hotUpdate from '../../components/HotUpdate/action';
import { updatePPKURL } from '../../utils/constants';
type Props = {};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
titleContainer: {
flex: 1,
alignSelf: 'stretch',
justifyContent: 'flex-end',
alignItems: 'center',
},
imageTitle: {
color: 'white',
backgroundColor: 'transparent',
fontSize: 24,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
class HotUpdatePage extends Component<Props> {
constructor(props) {
super(props);
this.state = {
hotPath: 'http://129.211.99.254:3333',
};
}
render() {
const { hotPath } = this.state;
return (
<View style={styles.container}>
<NavigationBar
title="热更新"
left={<BackButton />}
/>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<TextInput
defaultValue={hotPath}
onChangeText={(text) => {
this.setState({
hotPath: text,
});
}}
/>
<Button
title="热更新"
containerStyle={{ marginVertical: 10 }}
onPress={() => {
NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
{
received: 2,
total: 1,
hash: `${Math.random()}`,
path: `${this.state.hotPath}${updatePPKURL()}`,
});
}}
/>
</View>
</View>
);
}
}
function actionMapping(dispatch) {
return {
pushTo: compose(dispatch, push),
popTo: compose(dispatch, pop),
setShowDialog: compose(dispatch, hotUpdate.showDialog),
setPath: compose(dispatch, hotUpdate.setPath),
setHash: compose(dispatch, hotUpdate.setHash),
};
}
export default connect(null, actionMapping)(HotUpdatePage);
......@@ -47,7 +47,7 @@ class HomePage extends Component<Props> {
}
componentDidMount() : void {
this.listener = NativeAppEventEmitter.addListener('react_navigation_onTransitionEnd_call', () => console.log('onTransitionEnd_call'));
this.listener = NativeAppEventEmitter.addListener('react_navigation_onTransitionEnd_call', () => {});
}
componentWillUnmount() : void {
......
......@@ -108,11 +108,11 @@
},
{
"imgUrl": "https://ecustomer.tp95589.com/static/rn/src/img/icon_service_shishidai.png",
"tagUrl": "22",
"tagUrl": "HotUpdatePage",
"pageType": "RN",
"authorization": "1",
"login": "1",
"title": "实时贷",
"title": "热更新",
"detail": "menu=service&banner=https://ecustomer.tp95589.com/static/rn/src/img/pic_shishidai_banner2.png&content=借款人(保险服务密码所有人)以在太平人寿保险有限公司所持有的可借款保险合同的现金价值为质,同意开通“实时货”业务并在“实时货”业务有效期内可向保险公司申请借、还款。\n注:货款时,仅支持投、被保人均为本人及投保人为本人、协议签订及申请借款时被保人为未成年人的保单。\n",
"titleColor": "#333333",
"detailColor": "",
......
......@@ -10,7 +10,7 @@ import {
import FastImage from 'react-native-fast-image';
import { FlatGrid } from 'react-native-super-grid';
import Text from '../../components/Text';
import SwiperView from '../../components/Swiper';
import SwipeView from '../../components/Swiper';
/**
*
......@@ -70,19 +70,19 @@ export function renderBanner(props) {
//console.log('renderBanner', props);
return (
<View
key="SwiperView"
key="SwipeView"
style={{
height: props.height,
}}
>
<SwiperView
<SwipeView
height={props.height}
width={props.width}
>
{
props.data.map((item, index) => (swiperItem({ ...props, item })))
}
</SwiperView>
</SwipeView>
</View>
);
}
......
......@@ -3,10 +3,12 @@
*/
import nav from './BasicNavigator/reducer';
import hotUpdateLoading from './components/HotUpdate/reducer';
import theme from './theme/reducer';
const reducers = {
nav,
hotUpdateLoading,
theme,
};
......
......@@ -3,6 +3,7 @@
*/
import React from 'react';
import {Platform} from 'react-native';
export const MOCK = true;
......@@ -54,6 +55,11 @@ export function updateInfoURL(env?: ENV_TYPE = ENV) {
return `${staticResourceMapping[String(env)]}/rn/updateIXX.json?ver=${Math.random()}`;
}
export function updatePPKURL() {
return Platform.OS !== 'ios' ? `/android.1564381779981.ppk?ver=${Math.random()}`
: `/ios.1564381775405.ppk?ver=${Math.random()}`;
}
export const StoreContext = React.createContext({});
export const appFileDir = () => 'com.basic';
......
///**
// * @flow
// */
//import { Platform, Linking, NativeAppEventEmitter } from 'react-native'
//import { packageVersion, currentVersion } from 'react-native-update-mutlirn-hg'
//import md5 from 'md5'
//import { updateInfoURL, ENV } from './constants'
//import { HybridDevice, HotUpdate } from './native-utils'
//import Alert from './Alert'
//import { APIDeps } from './api/BasicAPIRequest'
//import {
// versionCheck, EQUAL, GREATER_THEN, LESS_THEN,
//} from './versionCheck'
//
//
///*
// {
// "ios": {
// "binary": "2.6.6",
// "url": "http://www.baidu.com",
// "patch": "http://127.0.0.1:8080/ios_2_6_7.ppk"
// },
// "android": {
// "binary": "1.6.2",
// "url": "http://www.baidu.com"
// "patch": "http://127.0.0.1:8080/android_2_6_7.ppk"
// }
// }
//*/
//const downloadUpdateInfo = async () => {
// // const response = await fetch(updateInfoURL(APIDeps.deviceInfo.env || 'DEV'))
// const response = await fetch(updateInfoURL(ENV))
// const updatePayload = await response.json()
//
// const platformPPK = updatePayload[Platform.OS] || {}
// APIDeps.ppkPath = platformPPK.patch
// return platformPPK
//}
//
//const downloadAndInstall = async (url, interactive) => {
// const hash = md5(url)
// const result = await HotUpdate.downloadUpdate({
// updateUrl: url,
// hashName: hash,
// })
// // console.log('downloadUpdate', result)
// if (!result) {
// // await HotUpdate.reloadUpdate({ hashName: hash })
// NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
// {
// received: 10,
// total: 1,
// hash,
// })
// if (interactive) {
// // Alert.alert('资源更新成功', null)
// }
// } else if (interactive) {
// NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
// {
// received: -1,
// total: 1,
// })
// // Alert.alert('下载失败,请稍后再试...', null)
// }
//}
//
//export async function downloadUpdate(url:string, interactive:boolean) {
// await downloadAndInstall(url, interactive)
//}
//
//export async function reloadUpdate(hash:string, interactive:boolean) {
// await HotUpdate.reloadUpdate({ hashName: hash })
// if (interactive) {
// // Alert.alert('资源更新成功', hash, null)
// }
// NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
// {
// received: -2,
// total: 1,
// })
// if (Platform.OS === 'android') {
// HybridDevice.restartApp()
// }
//}
//
//// function asyncAlert(message) {
//// return new Promise(success => {
//// Alert.alert(message, null, [{ text: '确定', onPress: success }])
//// })
//// }
//
export function markUpdateSuccess() {
//HotUpdate.markSuccess()
}
//
//export async function checkBinaryVersionAction() {
// const updateInfo = await downloadUpdateInfo()
// const { binary, url } = updateInfo || {}
//
// if (versionCheck(packageVersion, binary) && url) {
// if (Platform.OS === 'android') {
// HybridDevice.updateSysVersion(url)
// } else {
// Alert.alert('版本更新', '发现新版本', [{
// text: '更新',
// onPress: () => HybridDevice.updateSysVersion(url),
// }])
// }
// } else {
// Alert.alert('版本已是最新')
// }
//
// return []
//}
//
//export default async function (interactive: boolean = false) {
// if (__DEV__) {
// return
// }
//
// const updateInfo = await downloadUpdateInfo()
// // console.log(updateInfo)
// if (interactive) {
// //await asyncAlert(JSON.stringify({
// // packageVersion,
// // currentVersion,
// // updateInfo,
// //}))
// }
//
// const { binary, url, patch } = updateInfo || {}
//
//
// const result = versionCheck(packageVersion, binary)
//
// if (result === GREATER_THEN) {
// return
// }
//
// if (result === LESS_THEN && url) {
// // if (Platform.OS === 'android') {
// // HybridDevice.updateSysVersion(url)
// // } else {
// Alert.alert('版本更新', '发现新版本啦', [{
// text: '更新',
// onPress: () => Linking.openURL(url),
// }])
// // }
// return
// }
//
// if (result === EQUAL && patch && (currentVersion !== md5(patch))) {
// // if (interactive) {
// // await asyncAlert('发现新的系统资源,请更新......')
// // }
// // await downloadAndInstall(patch, interactive)
// NativeAppEventEmitter.emit('RCTHotUpdateDownloadProgress',
// {
// received: 2,
// total: 1,
// path: patch,
// })
// }
//}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment