├── .gitignore ├── Bu1.js ├── Bu2.js ├── IOS.js ├── IOS2.js ├── README.md ├── RNDemo.js ├── ServiceHot ├── SERVER_HOT ├── bundleFile │ ├── 1.0.0-Staging-index.android.bundle │ ├── 1.0.2-Staging-index.android.bundle │ └── v1.0.0-bu1.android.bundle ├── index.js └── public │ ├── 1.0.0-Staging-index.android.bundle.zip │ ├── 1.0.2-Staging-index.android.bundle.zip │ ├── console │ ├── index.css │ ├── index.html │ ├── index.js │ └── prejs │ │ ├── axios.js │ │ ├── bable.js │ │ ├── react.dom.js │ │ └── react.js │ └── v1.0.0-bu1.android.bundle.zip ├── android ├── app │ ├── .gitignore │ ├── build.gradle │ ├── my-release-key.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── myapprnn │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ ├── bu1.android.bundle │ │ │ ├── bu11.android.bundle │ │ │ ├── bu2.android.bundle │ │ │ ├── bundleJsAndAssets │ │ │ │ └── index.android.bundle │ │ │ ├── common.android 2.bundle │ │ │ ├── common.android.bundle │ │ │ ├── index.android 2.bundle │ │ │ ├── index.android.bundle │ │ │ ├── read.txt │ │ │ └── rn.android.bundle │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── myapprnn │ │ │ │ ├── Bu1Activity.java │ │ │ │ ├── Bu2Activity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainApplication.java │ │ │ │ ├── PreBaseInit.java │ │ │ │ ├── RNToolPackage.java │ │ │ │ └── RNToolsManager.java │ │ └── res │ │ │ ├── drawable-mdpi │ │ │ ├── src_assets_imgs_bigimage.png │ │ │ ├── src_assets_imgs_default.png │ │ │ ├── src_assets_imgs_test.png │ │ │ ├── src_modules_business1_assets_img_1024_500.png │ │ │ └── src_modules_main_assets_img_test.png │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable-xhdpi │ │ │ └── src_assets_imgs_default.png │ │ │ ├── drawable-xxhdpi │ │ │ └── src_assets_imgs_default.png │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ ├── activity_bu1.xml │ │ │ ├── activity_bu2.xml │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ └── data_extraction_rules.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── myapprnn │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── base.js ├── build.js ├── bundle ├── IOS.ios.bundle ├── IOS2.ios.bundle ├── assets │ └── src │ │ └── modules │ │ └── Business1 │ │ └── assets │ │ └── img │ │ └── 1024_500.png └── common.ios.bundle ├── cacheFile.json ├── common.js ├── common ├── hooks │ └── useServerHot.js ├── index.js ├── native │ └── index.js └── utils │ ├── index.js │ ├── navigation.js │ └── storage.js ├── config ├── ModuleIdConfig.json ├── bundleBuInfo.json ├── bundleCommonInfo.json ├── getModuleIdByIndex.json ├── platformMap.json ├── platformNameMap.json └── versionMap.json ├── doc ├── SERVER_HOT.md └── ServiceHot设计.drawio ├── index.js ├── ios ├── Podfile ├── Podfile.lock ├── myrnapp.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── myrnapp.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── myrnapp │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── RNToolPackage.h │ ├── RNToolPackage.m │ ├── ReactController.m │ ├── SceneDelegate.h │ ├── SceneDelegate.m │ ├── ViewController.h │ ├── ViewController.m │ ├── main.m │ └── myrnapp.xcdatamodeld │ │ ├── .xccurrentversion │ │ └── myrnapp.xcdatamodel │ │ └── contents ├── myrnappTests │ ├── Info.plist │ └── myrnappTests.m └── myrnappUITests │ ├── Info.plist │ └── myrnappUITests.m ├── metro.base.config.js ├── metro.common.config.js ├── metro.main.config.js ├── package.json ├── src ├── assets │ └── imgs │ │ ├── bigImage.png │ │ ├── default.png │ │ ├── default@2x.png │ │ ├── default@3x.png │ │ └── test.png └── modules │ ├── Business1 │ ├── assets │ │ └── img │ │ │ ├── 1024_500.png │ │ │ └── test.png │ └── index.js │ ├── Business2 │ └── index.js │ ├── Frame.js │ └── Main │ ├── TestNativeInfo.js │ ├── assets │ └── img │ │ └── test.png │ ├── index.js │ └── package.config.js ├── test └── index.md ├── utils.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | ios/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | 34 | # node.js 35 | # 36 | node_modules/ 37 | npm-debug.log 38 | yarn-error.log 39 | 40 | # BUCK 41 | buck-out/ 42 | \.buckd/ 43 | # 这个还是上传 ,业务开源项目嘛 44 | # *.keystore 45 | # !debug.keystore 46 | 47 | # fastlane 48 | # 49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 50 | # screenshots whenever they are needed. 51 | # For more information about the recommended setup visit: 52 | # https://docs.fastlane.tools/best-practices/source-control/ 53 | 54 | **/fastlane/report.xml 55 | **/fastlane/Preview.html 56 | **/fastlane/screenshots 57 | **/fastlane/test_output 58 | 59 | # Bundle artifact 60 | # *.jsbundle 暂且上传 供大家参考 61 | 62 | # Ruby / CocoaPods 63 | /ios/Pods/ 64 | /vendor/bundle/ 65 | -------------------------------------------------------------------------------- /Bu1.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AppRegistry } from "react-native"; 3 | import BU1 from "./src/modules/Business1"; 4 | import { bu1 } from "./app.json"; 5 | // 整个App 的骨架,基础包 更新要严格控制 6 | 7 | AppRegistry.registerComponent(bu1.name, () => BU1); 8 | -------------------------------------------------------------------------------- /Bu2.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AppRegistry } from "react-native"; 3 | import BU2 from "./src/modules/Business2"; 4 | import { bu2 } from "./app.json"; 5 | // 整个App 的骨架,基础包 更新要严格控制 6 | 7 | AppRegistry.registerComponent(bu2.name, () => BU2); 8 | -------------------------------------------------------------------------------- /IOS.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | AppRegistry, 4 | StyleSheet, 5 | Text, 6 | View, 7 | Button, 8 | } from 'react-native'; 9 | import NativeModule from './common/native'; 10 | const { changeActivity } = NativeModule; 11 | 12 | class RNHighScores extends React.Component { 13 | render() { 14 | return ( 15 | 16 | { 17 | changeActivity("IOS2") 18 | }} style ={styles.highScoresTitle}> 19 | 返回IOS2 20 | 21 | 22 | 23 | 24 | 25 | ); 26 | } 27 | } 28 | 29 | const styles = StyleSheet.create({ 30 | container: { 31 | flex: 1, 32 | justifyContent: 'center', 33 | alignItems: 'center', 34 | backgroundColor: '#FFFFFF' 35 | }, 36 | highScoresTitle: { 37 | fontSize: 20, 38 | textAlign: 'center', 39 | margin: 10 40 | }, 41 | scores: { 42 | textAlign: 'center', 43 | color: '#333333', 44 | marginBottom: 5 45 | } 46 | }); 47 | 48 | // Module name 49 | AppRegistry.registerComponent('IOS', () => RNHighScores); -------------------------------------------------------------------------------- /IOS2.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { 3 | AppRegistry, 4 | StyleSheet, 5 | Text, 6 | View, 7 | Image 8 | } from 'react-native'; 9 | import TestNativeInfo from './src/modules/Main/TestNativeInfo' 10 | import Imgx from "./src/modules/Business1/assets/img/1024_500.png"; 11 | import NativeModule from './common/native'; 12 | const { changeActivity } = NativeModule; 13 | 14 | class RNHighScores extends React.Component { 15 | render() { 16 | return ( 17 | 18 | { 19 | changeActivity("IOS") 20 | }} style={styles.highScoresTitle}> 21 | IOS bundle2 22 | 23 | 30 | 31 | 32 | {/* */} 33 | 34 | 35 | ); 36 | } 37 | } 38 | 39 | const styles = StyleSheet.create({ 40 | container: { 41 | flex: 1, 42 | justifyContent: 'center', 43 | alignItems: 'center', 44 | backgroundColor: '#FFFFFF' 45 | }, 46 | highScoresTitle: { 47 | fontSize: 20, 48 | textAlign: 'center', 49 | margin: 10 50 | }, 51 | scores: { 52 | textAlign: 'center', 53 | color: '#333333', 54 | marginBottom: 5 55 | }, 56 | img: { 57 | width: "100%", 58 | height: 600, 59 | }, 60 | }); 61 | 62 | AppRegistry.registerComponent('IOS2', () => RNHighScores); -------------------------------------------------------------------------------- /RNDemo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View, AppRegistry } from "react-native"; 3 | 4 | // 整个App 的骨架,基础包 更新要严格控制 5 | class BU1 extends React.Component { 6 | render() { 7 | return ( 8 | 9 | BU1 10 | 11 | ); 12 | } 13 | } 14 | 15 | const styles = StyleSheet.create({ 16 | container: { 17 | flex: 1, 18 | justifyContent: "center", 19 | height: 100, 20 | }, 21 | hello: { 22 | fontSize: 20, 23 | textAlign: "center", 24 | margin: 10, 25 | }, 26 | imgView: { 27 | width: "100%", 28 | }, 29 | img: { 30 | width: "100%", 31 | height: 600, 32 | }, 33 | flatContainer: { 34 | flex: 1, 35 | }, 36 | }); 37 | 38 | AppRegistry.registerComponent("Bu1Activity", () => BU1); 39 | -------------------------------------------------------------------------------- /ServiceHot/SERVER_HOT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/ServiceHot/SERVER_HOT -------------------------------------------------------------------------------- /ServiceHot/bundleFile/v1.0.0-bu1.android.bundle: -------------------------------------------------------------------------------- 1 | __d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=(n(r(d[1])),r(d[2])),u=n(r(d[3])),o=r(d[4]);t.AppRegistry.registerComponent(o.bu1.name,function(){return u.default})},20000000,[7,1,3,20000001,20000010]); 2 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=t(r(d[1])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=s(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=u?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(l,c,f):l[c]=t[c]}l.default=t,o&&o.set(t,l);return l})(r(d[2])),l=r(d[3]),u=t(r(d[4])),c=r(d[5]),f=r(d[6]);function s(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(s=function(t){return t?o:n})(t)}var y=l.StyleSheet.create({container:{flex:1,justifyContent:"center",height:100},hello:{fontSize:20,textAlign:"center",margin:10},imgView:{width:"100%"},img:{width:"100%",height:600},flatContainer:{flex:1},btn:{width:30,height:30}}),h=function(t){(0,o.useEffect)(function(){return h(),console.log("\u521d\u59cb\u5316"),function(){console.log("\u9500\u6bc1")}},[]);var s,h=(s=(0,n.default)(function*(){var t=yield c.navigation.getFromActivity();console.log("params",t)}),function(){return s.apply(this,arguments)});return(0,f.jsxs)(l.View,{style:y.container,children:[(0,f.jsx)(l.Text,{style:y.hello,children:"BU1 "}),(0,f.jsx)(l.Button,{title:"\u524d\u5f80BU2",onPress:function(){c.navigation.pushToActivity("Bu2Activity",{value:111})},style:y.btn}),(0,f.jsx)(l.ScrollView,{style:y.flatContainer,children:(0,f.jsx)(l.View,{style:y.imgView,children:(0,f.jsx)(l.Image,{resizeMethod:"resize",resizeMode:"contain",source:u.default,style:y.img})})})]})};e.default=h},20000001,[7,268,1,3,20000002,20000004,179]); 3 | __d(function(g,r,i,a,m,e,d){m.exports=r(d[0]).registerAsset({__packager_asset:!0,httpServerLocation:"/assets/src/modules/Business1/assets/img",width:1024,height:500,scales:[1],hash:"938f55d05f70c75063d310be556059e4",name:"1024_500",type:"png"})},20000002,[20000003]); 4 | __d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},20000003,[150]); 5 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.navigation=void 0,Object.defineProperty(e,"storageApp",{enumerable:!0,get:function(){return n.default}});var n=t(r(d[1])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=u(n);if(o&&o.has(t))return o.get(t);var f={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=p?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(f,c,l):f[c]=t[c]}f.default=t,o&&o.set(t,f);return f})(r(d[2]));function u(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(u=function(t){return t?o:n})(t)}e.navigation=o},20000004,[7,20000005,20000008]); 6 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var l=r(d[1]),n=new(t(r(d[2])).default)({size:1e3,storageBackend:l.AsyncStorage,defaultExpires:864e5,enableCache:!0});e.default=n},20000005,[7,3,20000006]); 7 | __d(function(g,r,i,a,_m,_e,d){var e=r(d[0]);Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var t=e(r(d[1])),n=e(r(d[2])),s=e(r(d[3])),o=r(d[4]),c=(function(){function e(){var t=this,s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if((0,n.default)(this,e),this._SIZE=s.size||1e3,this.sync=s.sync||{},this.defaultExpires=void 0!==s.defaultExpires?s.defaultExpires:864e5,this.enableCache=!1!==s.enableCache,this._s=s.storageBackend||null,this._innerVersion=11,this.cache={},this._s&&this._s.setItem)try{var o=this._s.setItem('__react_native_storage_test','test');this.isPromise=!(!o||!o.then)}catch(e){throw console.warn(e),delete this._s,e}else console.warn("Data would be lost after reload cause there is no storageBackend specified!\n \nEither use localStorage(for web) or AsyncStorage(for React Native) as a storageBackend.");this._mapPromise=this.getItem('map').then(function(e){t._m=t._checkMap(e&&JSON.parse(e)||{})})}return(0,s.default)(e,[{key:"getItem",value:function(e){return this._s?this.isPromise?this._s.getItem(e):Promise.resolve(this._s.getItem(e)):Promise.resolve()}},{key:"setItem",value:function(e,t){return this._s?this.isPromise?this._s.setItem(e,t):Promise.resolve(this._s.setItem(e,t)):Promise.resolve()}},{key:"removeItem",value:function(e){return this._s?this.isPromise?this._s.removeItem(e):Promise.resolve(this._s.removeItem(e)):Promise.resolve()}},{key:"_initMap",value:function(){return{innerVersion:this._innerVersion,index:0,__keys__:{}}}},{key:"_checkMap",value:function(e){return e&&e.innerVersion&&e.innerVersion===this._innerVersion?e:this._initMap()}},{key:"_getId",value:function(e,t){return e+'_'+t}},{key:"_saveToMap",value:function(e){var t=e.key,n=e.id,s=e.data,o=this._getId(t,n),c=this._m;if(void 0!==c[o])return this.enableCache&&(this.cache[o]=JSON.parse(s)),this.setItem('map_'+c[o],s);if(void 0!==c[c.index]){var h=c[c.index],u=h.split('_');delete c[h],this._removeIdInKey(u[0],u[1]),this.enableCache&&delete this.cache[h]}if(c[o]=c.index,c[c.index]=o,c.__keys__[t]=c.__keys__[t]||[],c.__keys__[t].push(n),this.enableCache){var l=JSON.parse(s);this.cache[o]=l}var y=c.index;++c.index===this._SIZE&&(c.index=0),this.setItem('map_'+y,s),this.setItem('map',JSON.stringify(c))}},{key:"save",value:function(e){var t=this,n=e.key,s=e.id,o=e.data,c=e.rawData,h=e.expires,u=void 0===h?this.defaultExpires:h;-1!==n.toString().indexOf('_')&&console.error('Please do not use "_" in key!');var l={rawData:o};if(void 0===o){if(void 0===c)return void console.error('"data" is required in save()!');console.warn('"rawData" is deprecated, please use "data" instead!'),l.rawData=c}var y=Date.now();if(null!==u&&(l.expires=y+u),l=JSON.stringify(l),void 0===s){if(this.enableCache){var _=JSON.parse(l);this.cache[n]=_}return this.setItem(n,l)}return-1!==s.toString().indexOf('_')&&console.error('Please do not use "_" in id!'),this._mapPromise.then(function(){return t._saveToMap({key:n,id:s,data:l})})}},{key:"getBatchData",value:function(e){var t=this;return Promise.all(e.map(function(e){return t.load(e)}))}},{key:"getBatchDataWithIds",value:(function(){var e=(0,t.default)(function*(e){var t=this,n=e.key,s=e.ids,o=e.syncInBackground,c=e.syncParams,h=s.map(function(e){return t.load({key:n,id:e,syncInBackground:o,autoSync:!1,batched:!0})}),u=yield Promise.all(h),l=[];if(u.forEach(function(e){void 0!==e.syncId&&l.push(e.syncId)}),l.length){var y=yield this.sync[n]({id:l,syncParams:c});return u.map(function(e){return e.syncId?y.shift():e})}return u});return function(t){return e.apply(this,arguments)}})()},{key:"_lookupGlobalItem",value:function(e){var t=this,n=e.key;return this.enableCache&&void 0!==this.cache[n]?this._loadGlobalItem(Object.assign({ret:this.cache[n]},e)):this.getItem(n).then(function(n){return t._loadGlobalItem(Object.assign({ret:n},e))})}},{key:"_loadGlobalItem",value:function(e){var t=e.key,n=e.ret,s=e.autoSync,c=e.syncInBackground,h=e.syncParams;if(null===n||void 0===n){if(s&&this.sync[t])return this.sync[t]({syncParams:h});throw new o.NotFoundError(JSON.stringify(e))}'string'==typeof n&&(n=JSON.parse(n),this.enableCache&&(this.cache[t]=n));var u=Date.now();if(n.expires { 19 | return new Promise((resolve, reject) => { 20 | db.all(query, (err, res) => { 21 | if (err) reject(err); 22 | resolve(res); 23 | }); 24 | }); 25 | }; 26 | 27 | const toZip = async (filename, filePath) => { 28 | return compressing.zip.compressFile( 29 | `${__dirname}/${filePath}`, 30 | `${__dirname}/public/${filename}` 31 | ); 32 | }; 33 | 34 | // 创建 35 | router_api.post("/create_app", async (req, res) => { 36 | const body = { 37 | appName: "", 38 | appDes: "", 39 | currentVersion: "", 40 | appKey: "", 41 | naive_version: "", 42 | ...req.body, 43 | }; 44 | 45 | const oldData = await promiseQuery("SELECT * from APP_INFO"); 46 | 47 | db.run( 48 | `INSERT INTO APP_INFO ( ID, APP_NAME, APP_DES, CURRENT_VERSION, APP_KEY, NATIVE_VERSION) 49 | VALUES (${oldData.length + 1}, '${body.appName}', '${body.appDes}', '${ 50 | body.currentVersion 51 | }', '${body.appKey}', '${body.naive_version}')`, 52 | (err, row) => { 53 | res.json({ 54 | data: null, 55 | success: true, 56 | message: "创建成功", 57 | }); 58 | } 59 | ); 60 | }); 61 | 62 | router_api.post("/create_module", async (req, res) => { 63 | const body = { 64 | module: "", 65 | platform: "", 66 | app_id: "", 67 | ...req.body, 68 | }; 69 | 70 | const oldData = await promiseQuery("SELECT * from MODULE_INFO"); 71 | 72 | db.run( 73 | `INSERT INTO MODULE_INFO ( ID, MODULE, PLATFORM, APP_INFO_ID) 74 | VALUES (${oldData.length + 1}, '${body.module}','${body.platform}', '${ 75 | body.app_id 76 | }')`, 77 | (err, row) => { 78 | res.json({ 79 | data: null, 80 | success: true, 81 | message: "创建成功", 82 | }); 83 | } 84 | ); 85 | }); 86 | 87 | router_api.post("/create_version_info", async (req, res) => { 88 | const body = { 89 | version: "", 90 | file_path: "", 91 | des: "", 92 | type: "", 93 | module_id: "", 94 | is_active: "", 95 | file_name: "", 96 | ...req.body, 97 | }; 98 | 99 | const oldData = await promiseQuery("SELECT * from VERSION_INFO"); 100 | db.run( 101 | `INSERT INTO VERSION_INFO (ID, VERSION, FILE_PATH, DES, TYPE, MODULE_ID, IS_ACTIVE, FILENAME ) 102 | VALUES (${oldData.length + 1}, '${body.version}', '${body.file_path}', '${ 103 | body.des 104 | }', '${body.type}', '${body.module_id}', ${body.is_active}, '${ 105 | body.file_name 106 | }' )`, 107 | (err, row) => { 108 | res.json({ 109 | data: null, 110 | success: true, 111 | message: "创建成功", 112 | }); 113 | } 114 | ); 115 | }); 116 | 117 | // 获取 118 | router_api.get("/app_list", async (req, res) => { 119 | const data = await promiseQuery("SELECT * from APP_INFO"); 120 | res.json({ 121 | data: data, 122 | success: true, 123 | message: "", 124 | }); 125 | }); 126 | 127 | router_api.get("/module_list", async (req, res) => { 128 | const data = await promiseQuery( 129 | `SELECT * from MODULE_INFO WHERE APP_INFO_ID = ${req.query.id}` 130 | ); 131 | res.json({ 132 | data: data, 133 | success: true, 134 | message: "", 135 | }); 136 | }); 137 | 138 | router_api.get("/version_list", async (req, res) => { 139 | const data = await promiseQuery( 140 | `SELECT * FROM 141 | MODULE_INFO INNER JOIN VERSION_INFO 142 | ON MODULE_INFO.ID = VERSION_INFO.MODULE_ID WHERE MODULE_ID = ${req.query.id};` 143 | ); 144 | res.json({ 145 | data: data, 146 | success: true, 147 | message: "", 148 | }); 149 | }); 150 | 151 | // 修改 成当前活动的模块 152 | router_api.put("/update_active_bundle", async (req, res) => { 153 | // 清空其它的 其实这个做法不好,有机会你们可以优化优化 154 | db.run( 155 | ` 156 | UPDATE VERSION_INFO SET IS_ACTIVE = 0 WHERE ID=${req.body.old_id} 157 | `, 158 | (err, it) => { 159 | // 设置自己的 160 | db.run(` 161 | UPDATE VERSION_INFO SET IS_ACTIVE = 1 WHERE ID=${req.body.id} 162 | `); 163 | res.json({ 164 | data: null, 165 | success: true, 166 | message: "修改成功", 167 | }); 168 | } 169 | ); 170 | }); 171 | 172 | router_api.post("/update_bundle", async (req, res) => { 173 | // 上传的文件在req.files中 174 | const version = req.query.version; 175 | const type = req.query.type; 176 | const filename = `bundleFile/${version}-${type}-${req.files[0].originalname}`; 177 | 178 | fs.rename(req.files[0].path, filename, async (err) => { 179 | if (err) { 180 | res.send({ 181 | data: null, 182 | success: false, 183 | message: "上传失败", 184 | }); 185 | } else { 186 | await toZip( 187 | `${version}-${type}-${req.files[0].originalname}.zip`, 188 | filename 189 | ); 190 | res.send({ 191 | data: { 192 | path: `/file/${version}-${type}-${req.files[0].originalname}.zip`, 193 | filename: `${version}-${type}-${req.files[0].originalname}.zip`, 194 | }, 195 | success: true, 196 | message: "上传成功", 197 | }); 198 | } 199 | }); 200 | }); 201 | 202 | // 方便清除测试数据 203 | router_api.delete("/cleanInfo", (req, res) => { 204 | db.run("DELETE FROM APP_INFO"); 205 | db.run("DELETE FROM VERSION_INFO"); 206 | db.run("DELETE FROM MODULE_INFO"); 207 | res.json({ 208 | data: null, 209 | success: true, 210 | message: "删除完成", 211 | }); 212 | }); 213 | 214 | // 给APP 的 API 用于判断 是否需要升级 ......todo 215 | router_api.get("/version_info", async (req, res) => { 216 | const params = { 217 | oldVersion: "", 218 | pageModule: "", 219 | type: "", 220 | appKey: "", 221 | platform:"", 222 | ...req.query, 223 | }; 224 | // 查询到当前的APP 225 | const appInfo = await promiseQuery( 226 | `SELECT * FROM APP_INFO WHERE APP_KEY = '${params.appKey}'` 227 | ); 228 | 229 | // 查询到当前的模块 ( 指定平台 ) 230 | const moduleInfo = await promiseQuery( 231 | `SELECT * FROM APP_INFO INNER JOIN MODULE_INFO ON APP_INFO.ID=MODULE_INFO.APP_INFO_ID WHERE APP_INFO_ID=${appInfo[0].ID} AND PLATFORM='${params.platform}' AND MODULE = '${params.pageModule}'` 232 | ) 233 | 234 | // 查询当前 module 下的 指定type 下的 active 的版本 235 | const activeVersion = await promiseQuery( 236 | `SELECT * FROM MODULE_INFO INNER JOIN VERSION_INFO ON MODULE_INFO.ID=VERSION_INFO.MODULE_ID WHERE MODULE_ID=${moduleInfo[0].ID} AND TYPE='${params.type}' AND IS_ACTIVE=1` 237 | ) 238 | 239 | 240 | // 对比是否需要更新 当前版本 241 | if(!activeVersion.length) { 242 | res.json({ 243 | data: { 244 | isNeedRefresh: false, 245 | }, 246 | success: true, 247 | message: "当前版本一致 不需要更新", 248 | }) 249 | return 250 | } 251 | 252 | if (activeVersion[0].VERSION === params.oldVersion ) { 253 | res.json({ 254 | data: { 255 | isNeedRefresh: false, 256 | }, 257 | success: true, 258 | message: "当前版本一致 不需要更新", 259 | }); 260 | return; 261 | } 262 | 263 | res.json({ 264 | data: { 265 | newVersion: activeVersion[0].VERSION, 266 | downloadPathL: activeVersion[0].FILE_PATH, 267 | module: activeVersion[0].MODULE, 268 | type: activeVersion[0].TYPE, 269 | isNeedRefresh: true, 270 | }, 271 | success: true, 272 | message: "请更新你的版本", 273 | }); 274 | }); 275 | 276 | app.use("/api", router_api); 277 | 278 | app.use("/file", express.static(path.join(__dirname, "public"))); 279 | 280 | app.listen(8085); 281 | -------------------------------------------------------------------------------- /ServiceHot/public/1.0.0-Staging-index.android.bundle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/ServiceHot/public/1.0.0-Staging-index.android.bundle.zip -------------------------------------------------------------------------------- /ServiceHot/public/1.0.2-Staging-index.android.bundle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/ServiceHot/public/1.0.2-Staging-index.android.bundle.zip -------------------------------------------------------------------------------- /ServiceHot/public/console/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | li { 7 | list-style: none; 8 | } 9 | 10 | iframe { 11 | display: none; 12 | } 13 | 14 | .app-container { 15 | margin: 0 auto; 16 | padding: 12px; 17 | overflow: auto; 18 | width: 1500px; 19 | background-color: aqua; 20 | } 21 | 22 | .app-header { 23 | padding-left: 12px; 24 | font-size: 18px; 25 | 26 | } 27 | .app-center { 28 | margin-top: 12px; 29 | background-color: skyblue; 30 | padding: 12px; 31 | } 32 | 33 | .list-container { 34 | background-color: skyblue; 35 | display: flex; 36 | flex-direction: column; 37 | justify-content: flex-start; 38 | padding: 8px; 39 | } 40 | 41 | .list-item { 42 | background-color: pink; 43 | display: flex; 44 | flex-direction: row; 45 | justify-content: space-around; 46 | align-items: center; 47 | padding: 8px; 48 | margin-bottom: 8px; 49 | } 50 | 51 | .item-span{ 52 | font-size: 14px; 53 | 54 | } 55 | 56 | .item-btn { 57 | font-size: 18px; 58 | } 59 | 60 | .form-example { 61 | width: 268px; 62 | display: flex; 63 | justify-content: space-between; 64 | margin-bottom: 8px; 65 | } 66 | 67 | .form-container { 68 | display: flex; 69 | justify-content: space-around; 70 | margin-top: 22px; 71 | background-color: #fff; 72 | padding: 12px; 73 | } -------------------------------------------------------------------------------- /ServiceHot/public/console/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
Loading.....
23 | 24 | 26 | 27 | -------------------------------------------------------------------------------- /ServiceHot/public/console/index.js: -------------------------------------------------------------------------------- 1 | const { useState, useEffect, useReducer, useRef } = React; 2 | const http = axios.create({ 3 | baseURL: "http://localhost:8085/api/", 4 | timeout: 2000, 5 | }); 6 | const VersionTypeList = (props) => { 7 | const { currentTypeList, toVersionList, setRouter } = props; 8 | const [type, setType] = useState("ANDROID"); 9 | 10 | return ( 11 |
12 |
13 | 21 | 22 | 30 | 38 |
39 | {currentTypeList 40 | .filter((it) => it.PLATFORM === type) 41 | .map((item, index) => { 42 | return ( 43 |
44 |
{item.ID}
45 |
{item.MODULE}
46 |
{item.PLATFORM}
47 | 55 |
56 | ); 57 | })} 58 |
59 | ); 60 | }; 61 | 62 | const VersionList = (props) => { 63 | const { versionList, setRouter, setActiveVersion } = props; 64 | const [type, setType] = useState("Staging"); 65 | 66 | console.log('versionList',versionList); 67 | 68 | return ( 69 |
70 |
71 | 79 | 87 | 95 |
96 | {versionList 97 | .filter((it) => it.TYPE === type) 98 | .map((item, index) => { 99 | return ( 100 |
101 |
{item.MODULE}
102 |
{item.VERSION}
103 |
{item.FILE_PATH}
104 |
{item.FILENAME}
105 |
{ Boolean(item.IS_ACTIVE) && "Active" }
106 | 119 |
120 | ); 121 | })} 122 |
123 | ); 124 | }; 125 | 126 | const AppList = (props) => { 127 | const { list, toTypeList } = props; 128 | return ( 129 |
130 |
131 |
名称
132 |
介绍
133 |
KEY
134 |
当前Native 版本
135 |
操作
136 |
137 | {list.map((item, index) => { 138 | return ( 139 |
140 |
{item.APP_NAME}
141 |
{item.APP_DES}
142 |
{item.APP_KEY}
143 |
{item.NATIVE_VERSION}
144 | 152 |
153 | ); 154 | })} 155 |
156 | ); 157 | }; 158 | 159 | // 创建APP 160 | const CreateAPPForm = (props) => { 161 | const { create } = props; 162 | const createApp = () => { 163 | const data = { 164 | appName: document.forms["createApp"]["appName"].value, 165 | appDes: document.forms["createApp"]["appDes"].value, 166 | currentVersion: document.forms["createApp"]["currentVersion"].value, 167 | appKey: document.forms["createApp"]["appKey"].value, 168 | naive_version: document.forms["createApp"]["naive_version"].value, 169 | }; 170 | create(data); 171 | }; 172 | 173 | return ( 174 |
175 |
{ 180 | console.log("e", e); 181 | createApp(); 182 | }} 183 | > 184 |
185 | 186 | 187 |
188 | 189 |
190 | 191 | 192 |
193 | 194 |
195 | 196 | 202 |
203 | 204 |
205 | 206 | 207 |
208 | 209 |
210 | 211 | 212 |
213 | 214 |
215 | 216 |
217 |
218 |
219 | ); 220 | }; 221 | 222 | // 创建模块 223 | const CreateModule = (props) => { 224 | const { create, currentApp } = props; 225 | const createModule = () => { 226 | const data = { 227 | module: document.forms["CreateModule"]["module"].value, 228 | platform: document.forms["CreateModule"]["platform"].value, 229 | app_id: currentApp.ID, 230 | }; 231 | create(data); 232 | }; 233 | 234 | return ( 235 |
236 |
242 |
243 | 244 | 245 |
246 | 247 |
248 | 249 | 250 |
251 | 252 |
253 | 254 |
255 |
256 |
257 | ); 258 | }; 259 | 260 | // 创建版本 261 | const CreateVersionForm = (props) => { 262 | const { create, currentModule } = props; 263 | const [preState, setState] = useState({ 264 | file_name: "", 265 | file_path: "", 266 | type: "", 267 | }); 268 | const createApp = () => { 269 | const data = { 270 | version: document.forms["CreateVersionForm"]["version"].value, 271 | file_path: preState.file_path, 272 | des: document.forms["CreateVersionForm"]["des"].value, 273 | type: preState.type, 274 | module_id: currentModule.ID, 275 | is_active: 0, // 0 || 1 276 | file_name: preState.file_name, 277 | }; 278 | create(data); 279 | }; 280 | 281 | const onUpdate = async (e) => { 282 | if( !e.target.files.length ) return; 283 | 284 | const files = e.target.files[0]; 285 | const formData = new FormData(); 286 | formData.append("files", files); 287 | const version = document.forms["CreateVersionForm"]["version"].value 288 | const data = await http.post( 289 | `/update_bundle?version=${version}&type=${preState.type}`, 290 | formData, 291 | { 292 | "Content-Type": "multipart/form-data;charset=utf-8", 293 | } 294 | ); 295 | 296 | setState((old) => ({ 297 | ...old, 298 | file_name: data.data.data.filename, 299 | file_path: data.data.data.path, 300 | })); 301 | }; 302 | 303 | return ( 304 |
305 |
{ 310 | 311 | // }} 312 | > 313 |
314 | 315 | 316 |
317 | 318 |
319 | 320 | 321 |
322 | 323 | {/*
324 | 325 |
*/} 326 |
327 | 328 |
329 | 330 | { 334 | setState((old) => ({ 335 | ...old, 336 | type: e.target.checked ? "Staging" : "Release", 337 | })); 338 | }} 339 | > 340 |
341 | 342 |
343 | 344 | 351 |
352 | 353 |
354 | ); 355 | }; 356 | 357 | const initAppInfo = { 358 | appList: [], 359 | currentTypeList: [], 360 | currentTypeVersionList: [], 361 | 362 | currentModule: {}, 363 | currentApp: {}, 364 | }; 365 | 366 | const reducer = (prevState, action) => { 367 | const { type, state } = action; 368 | switch (type) { 369 | case "APP_LIST": 370 | return { ...prevState, appList: state }; 371 | case "CURRENT_TYPE": 372 | return { 373 | ...prevState, 374 | currentTypeList: state, 375 | }; 376 | case "CURRENT_TYPE_VERSION_LIST": 377 | return { 378 | ...prevState, 379 | currentTypeVersionList: state, 380 | }; 381 | case "CURRENT_MODULE": 382 | return { 383 | ...prevState, 384 | currentModule: state, 385 | }; 386 | case "CURRENT_APP": 387 | return { 388 | ...prevState, 389 | currentApp: state, 390 | }; 391 | default: 392 | return { ...prevState }; 393 | } 394 | }; 395 | 396 | const App = () => { 397 | const [appStatus, dispatchDispatch] = useReducer(reducer, initAppInfo); 398 | const [router, setRouter] = useState("/home"); 399 | 400 | useEffect(() => { 401 | init(); 402 | }, []); 403 | 404 | const init = async () => { 405 | const value = await http.get("/app_list"); 406 | dispatchDispatch({ 407 | type: "APP_LIST", 408 | state: value.data.data, 409 | }); 410 | }; 411 | 412 | const routerChanger = (path) => { 413 | // path /home /versionTypeList /versionList 414 | setRouter(path); 415 | }; 416 | 417 | const toTypeList = async (item) => { 418 | // const value = await http.get("/app_list"); 419 | dispatchDispatch({ 420 | type: "CURRENT_APP", 421 | state: item, 422 | }); 423 | await loadModule(item.ID); 424 | routerChanger("/versionTypeList"); 425 | }; 426 | 427 | const toVersionList = async (item) => { 428 | dispatchDispatch({ 429 | type: "CURRENT_MODULE", 430 | state: item, 431 | }); 432 | await loadVersion(item.ID); 433 | routerChanger("/versionList"); 434 | }; 435 | 436 | // createApp 437 | const create = async (data) => { 438 | await http.post("/create_app", data); 439 | await await init(); 440 | }; 441 | 442 | const createModule = async (data) => { 443 | await http.post("/create_module", data); 444 | await loadModule() 445 | }; 446 | 447 | const createVersion = async (data) => { 448 | await http.post("/create_version_info", data); 449 | await loadVersion() 450 | }; 451 | 452 | const setActiveVersion = async (data) => { 453 | const { old_id, id } = data; 454 | await http.put(`/update_active_bundle`,data); 455 | await loadVersion() 456 | }; 457 | 458 | const loadModule = async (id) => { 459 | const value = await http.get( 460 | `/module_list?id=${id || appStatus.currentApp.ID || 1}` 461 | ); 462 | dispatchDispatch({ 463 | type: "CURRENT_TYPE", 464 | state: value.data.data, 465 | }); 466 | }; 467 | 468 | const loadVersion = async (id) => { 469 | const value = await http.get( 470 | `/version_list?id=${id || appStatus.currentModule.ID || 1}` 471 | ); 472 | dispatchDispatch({ 473 | type: "CURRENT_TYPE_VERSION_LIST", 474 | state: value.data.data, 475 | }); 476 | }; 477 | 478 | 479 | 480 | return ( 481 |
482 |
483 | {router === "/home" && "APP列表"} 484 | {router === "/versionTypeList" && "APP所有模块"} 485 | {router === "/versionList" && "APP模块Version列表"} 486 |
487 |
488 | {router === "/home" && ( 489 | 495 | )} 496 | 497 | {router === "/versionTypeList" && ( 498 | 503 | )} 504 | {router === "/versionList" && ( 505 | 510 | )} 511 |
512 | 513 | {/* 创建APP / 上传文件 /创建新版本 */} 514 |
515 | 516 | 517 | 521 | 525 |
526 |
527 | ); 528 | }; 529 | 530 | // 挂载, 531 | ReactDOM.render(, document.getElementById("app")); 532 | -------------------------------------------------------------------------------- /ServiceHot/public/v1.0.0-bu1.android.bundle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/ServiceHot/public/v1.0.0-bu1.android.bundle.zip -------------------------------------------------------------------------------- /android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdk 32 7 | 8 | defaultConfig { 9 | applicationId "com.example.myapprnn" 10 | minSdk 21 11 | targetSdk 32 12 | versionCode 1 13 | versionName "1.0.0" // CodePush 要求使用三位数 而非默认的两位数 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | signingConfigs { 18 | release { 19 | if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) { 20 | storeFile file(MYAPP_RELEASE_STORE_FILE) 21 | storePassword MYAPP_RELEASE_STORE_PASSWORD 22 | keyAlias MYAPP_RELEASE_KEY_ALIAS 23 | keyPassword MYAPP_RELEASE_KEY_PASSWORD 24 | } 25 | } 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 31 | signingConfig signingConfigs.release 32 | } 33 | 34 | releaseStaging.initWith(release) 35 | releaseStaging { 36 | matchingFallbacks = ['release'] 37 | } 38 | 39 | } 40 | compileOptions { 41 | sourceCompatibility JavaVersion.VERSION_1_8 42 | targetCompatibility JavaVersion.VERSION_1_8 43 | } 44 | } 45 | 46 | dependencies { 47 | 48 | implementation 'androidx.appcompat:appcompat:1.5.1' 49 | implementation 'com.google.android.material:material:1.6.1' 50 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 51 | testImplementation 'junit:junit:4.13.2' 52 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 53 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 54 | // 添加 RN 和JSC 引擎 55 | implementation "com.facebook.react:react-native:+" // From node_modules 56 | implementation "org.webkit:android-jsc:+" 57 | } 58 | 59 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 60 | -------------------------------------------------------------------------------- /android/app/my-release-key.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/my-release-key.keystore -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android/app/src/androidTest/java/com/example/myapprnn/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.myapprnn; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.example.myapprnn", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 23 | 27 | 32 | 33 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /android/app/src/main/assets/bu1.android.bundle: -------------------------------------------------------------------------------- 1 | __d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=(n(r(d[1])),r(d[2])),u=n(r(d[3])),o=r(d[4]);t.AppRegistry.registerComponent(o.bu1.name,function(){return u.default})},20000000,[7,1,3,20000001,20000010]); 2 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=t(r(d[1])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=s(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=u?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(l,c,f):l[c]=t[c]}l.default=t,o&&o.set(t,l);return l})(r(d[2])),l=r(d[3]),u=t(r(d[4])),c=r(d[5]),f=r(d[6]);function s(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(s=function(t){return t?o:n})(t)}var y=l.StyleSheet.create({container:{flex:1,justifyContent:"center",height:100},hello:{fontSize:20,textAlign:"center",margin:10},imgView:{width:"100%"},img:{width:"100%",height:600},flatContainer:{flex:1},btn:{width:30,height:30}}),h=function(t){(0,o.useEffect)(function(){return h(),console.log("\u521d\u59cb\u5316"),function(){console.log("\u9500\u6bc1")}},[]);var s,h=(s=(0,n.default)(function*(){var t=yield c.navigation.getFromActivity();console.log("params",t)}),function(){return s.apply(this,arguments)});return(0,f.jsxs)(l.View,{style:y.container,children:[(0,f.jsx)(l.Text,{style:y.hello,children:"BU1 "}),(0,f.jsx)(l.Button,{title:"\u524d\u5f80BU2",onPress:function(){c.navigation.pushToActivity("Bu2Activity",{value:111})},style:y.btn}),(0,f.jsx)(l.ScrollView,{style:y.flatContainer,children:(0,f.jsx)(l.View,{style:y.imgView,children:(0,f.jsx)(l.Image,{resizeMethod:"resize",resizeMode:"contain",source:u.default,style:y.img})})})]})};e.default=h},20000001,[7,268,1,3,20000002,20000004,179]); 3 | __d(function(g,r,i,a,m,e,d){m.exports=r(d[0]).registerAsset({__packager_asset:!0,httpServerLocation:"/assets/src/modules/Business1/assets/img",width:1024,height:500,scales:[1],hash:"938f55d05f70c75063d310be556059e4",name:"1024_500",type:"png"})},20000002,[20000003]); 4 | __d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},20000003,[150]); 5 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.navigation=void 0,Object.defineProperty(e,"storageApp",{enumerable:!0,get:function(){return n.default}});var n=t(r(d[1])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=u(n);if(o&&o.has(t))return o.get(t);var f={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=p?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(f,c,l):f[c]=t[c]}f.default=t,o&&o.set(t,f);return f})(r(d[2]));function u(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(u=function(t){return t?o:n})(t)}e.navigation=o},20000004,[7,20000005,20000008]); 6 | __d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var l=r(d[1]),n=new(t(r(d[2])).default)({size:1e3,storageBackend:l.AsyncStorage,defaultExpires:864e5,enableCache:!0});e.default=n},20000005,[7,3,20000006]); 7 | __d(function(g,r,i,a,_m,_e,d){var e=r(d[0]);Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var t=e(r(d[1])),n=e(r(d[2])),s=e(r(d[3])),o=r(d[4]),c=(function(){function e(){var t=this,s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if((0,n.default)(this,e),this._SIZE=s.size||1e3,this.sync=s.sync||{},this.defaultExpires=void 0!==s.defaultExpires?s.defaultExpires:864e5,this.enableCache=!1!==s.enableCache,this._s=s.storageBackend||null,this._innerVersion=11,this.cache={},this._s&&this._s.setItem)try{var o=this._s.setItem('__react_native_storage_test','test');this.isPromise=!(!o||!o.then)}catch(e){throw console.warn(e),delete this._s,e}else console.warn("Data would be lost after reload cause there is no storageBackend specified!\n \nEither use localStorage(for web) or AsyncStorage(for React Native) as a storageBackend.");this._mapPromise=this.getItem('map').then(function(e){t._m=t._checkMap(e&&JSON.parse(e)||{})})}return(0,s.default)(e,[{key:"getItem",value:function(e){return this._s?this.isPromise?this._s.getItem(e):Promise.resolve(this._s.getItem(e)):Promise.resolve()}},{key:"setItem",value:function(e,t){return this._s?this.isPromise?this._s.setItem(e,t):Promise.resolve(this._s.setItem(e,t)):Promise.resolve()}},{key:"removeItem",value:function(e){return this._s?this.isPromise?this._s.removeItem(e):Promise.resolve(this._s.removeItem(e)):Promise.resolve()}},{key:"_initMap",value:function(){return{innerVersion:this._innerVersion,index:0,__keys__:{}}}},{key:"_checkMap",value:function(e){return e&&e.innerVersion&&e.innerVersion===this._innerVersion?e:this._initMap()}},{key:"_getId",value:function(e,t){return e+'_'+t}},{key:"_saveToMap",value:function(e){var t=e.key,n=e.id,s=e.data,o=this._getId(t,n),c=this._m;if(void 0!==c[o])return this.enableCache&&(this.cache[o]=JSON.parse(s)),this.setItem('map_'+c[o],s);if(void 0!==c[c.index]){var h=c[c.index],u=h.split('_');delete c[h],this._removeIdInKey(u[0],u[1]),this.enableCache&&delete this.cache[h]}if(c[o]=c.index,c[c.index]=o,c.__keys__[t]=c.__keys__[t]||[],c.__keys__[t].push(n),this.enableCache){var l=JSON.parse(s);this.cache[o]=l}var y=c.index;++c.index===this._SIZE&&(c.index=0),this.setItem('map_'+y,s),this.setItem('map',JSON.stringify(c))}},{key:"save",value:function(e){var t=this,n=e.key,s=e.id,o=e.data,c=e.rawData,h=e.expires,u=void 0===h?this.defaultExpires:h;-1!==n.toString().indexOf('_')&&console.error('Please do not use "_" in key!');var l={rawData:o};if(void 0===o){if(void 0===c)return void console.error('"data" is required in save()!');console.warn('"rawData" is deprecated, please use "data" instead!'),l.rawData=c}var y=Date.now();if(null!==u&&(l.expires=y+u),l=JSON.stringify(l),void 0===s){if(this.enableCache){var _=JSON.parse(l);this.cache[n]=_}return this.setItem(n,l)}return-1!==s.toString().indexOf('_')&&console.error('Please do not use "_" in id!'),this._mapPromise.then(function(){return t._saveToMap({key:n,id:s,data:l})})}},{key:"getBatchData",value:function(e){var t=this;return Promise.all(e.map(function(e){return t.load(e)}))}},{key:"getBatchDataWithIds",value:(function(){var e=(0,t.default)(function*(e){var t=this,n=e.key,s=e.ids,o=e.syncInBackground,c=e.syncParams,h=s.map(function(e){return t.load({key:n,id:e,syncInBackground:o,autoSync:!1,batched:!0})}),u=yield Promise.all(h),l=[];if(u.forEach(function(e){void 0!==e.syncId&&l.push(e.syncId)}),l.length){var y=yield this.sync[n]({id:l,syncParams:c});return u.map(function(e){return e.syncId?y.shift():e})}return u});return function(t){return e.apply(this,arguments)}})()},{key:"_lookupGlobalItem",value:function(e){var t=this,n=e.key;return this.enableCache&&void 0!==this.cache[n]?this._loadGlobalItem(Object.assign({ret:this.cache[n]},e)):this.getItem(n).then(function(n){return t._loadGlobalItem(Object.assign({ret:n},e))})}},{key:"_loadGlobalItem",value:function(e){var t=e.key,n=e.ret,s=e.autoSync,c=e.syncInBackground,h=e.syncParams;if(null===n||void 0===n){if(s&&this.sync[t])return this.sync[t]({syncParams:h});throw new o.NotFoundError(JSON.stringify(e))}'string'==typeof n&&(n=JSON.parse(n),this.enableCache&&(this.cache[t]=n));var u=Date.now();if(n.expires packages; 17 | private ReactInstanceManager cacheReactInstanceManager; 18 | private Boolean isload = false; 19 | 20 | private static MainApplication mApp; @Override 21 | public void onCreate() { 22 | super.onCreate(); 23 | SoLoader.init(this, /* native exopackage */ false); 24 | mApp = this; 25 | 26 | packages = new PackageList(this).getPackages(); 27 | packages.add(new RNToolPackage()); 28 | 29 | cacheReactInstanceManager = ReactInstanceManager.builder() 30 | .setApplication(this) 31 | .addPackages(packages) 32 | .setJSBundleFile("assets://common.android.bundle") 33 | .setInitialLifecycleState(LifecycleState.BEFORE_CREATE).build(); 34 | 35 | } 36 | 37 | public static MainApplication getInstance(){ 38 | return mApp; 39 | } 40 | 41 | // 获取 已经缓存过的 rcInstanceManager 42 | public ReactInstanceManager getRcInstanceManager () { 43 | return this.cacheReactInstanceManager; 44 | } 45 | 46 | 47 | public void setIsLoad(Boolean isload) { 48 | this.isload = isload; 49 | } 50 | 51 | public boolean getIsLoad(){ 52 | return this.isload; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/myapprnn/PreBaseInit.java: -------------------------------------------------------------------------------- 1 | package com.example.myapprnn; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.provider.Settings; 8 | import android.util.Log; 9 | import android.view.KeyEvent; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import com.facebook.react.ReactInstanceManager; 15 | import com.facebook.react.ReactRootView; 16 | import com.facebook.react.bridge.CatalystInstance; 17 | import com.facebook.react.bridge.CatalystInstanceImpl; 18 | import com.facebook.react.bridge.ReactApplicationContext; 19 | import com.facebook.react.bridge.ReactContext; 20 | import com.facebook.react.common.LifecycleState; 21 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 22 | import com.facebook.soloader.SoLoader; 23 | 24 | public class PreBaseInit extends AppCompatActivity implements DefaultHardwareBackBtnHandler { 25 | private final int OVERLAY_PERMISSION_REQ_CODE = 1; 26 | private ReactRootView mReactRootView; 27 | private ReactInstanceManager mReactInstanceManager; 28 | 29 | public String getJSBundleAssetName(){ 30 | return "index.android.bundle"; 31 | }; 32 | 33 | public String getJsModulePathPath(){ 34 | return "index"; 35 | }; 36 | 37 | public String getResName(){ 38 | return "MyReactNativeApp"; 39 | }; 40 | 41 | public void preInit () {} 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | this.preInit(); 46 | super.onCreate(savedInstanceState); 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 48 | if (!Settings.canDrawOverlays(this)) { 49 | Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, 50 | Uri.parse("package:" + getPackageName())); 51 | startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); 52 | } 53 | } 54 | SoLoader.init(this, false); 55 | 56 | if( BuildConfig.DEBUG ){ 57 | mReactRootView = new ReactRootView(this); 58 | mReactInstanceManager = ReactInstanceManager.builder() 59 | .setApplication(getApplication()) 60 | .setCurrentActivity(this) 61 | .setBundleAssetName(getJSBundleAssetName()) 62 | .setJSMainModulePath(getJsModulePathPath()) 63 | .addPackages(MainApplication.getInstance().packages) 64 | .setUseDeveloperSupport(true) 65 | .setInitialLifecycleState(LifecycleState.RESUMED) 66 | .build(); 67 | 68 | mReactRootView.startReactApplication(mReactInstanceManager, getResName(), null); 69 | setContentView(mReactRootView); 70 | return; 71 | } 72 | 73 | mReactInstanceManager = MainApplication.getInstance().getRcInstanceManager(); 74 | mReactInstanceManager.onHostResume(this, this); 75 | mReactRootView = new ReactRootView(this); 76 | 77 | mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { 78 | @Override 79 | public void onReactContextInitialized(ReactContext context) { 80 | MainApplication.getInstance().setIsLoad(true); 81 | 82 | //加载业务包 83 | ReactContext mContext = mReactInstanceManager.getCurrentReactContext(); 84 | CatalystInstance instance = mContext.getCatalystInstance(); 85 | 86 | loadForSystemOrAssets(instance,context); 87 | 88 | mReactRootView.startReactApplication(mReactInstanceManager, getResName(), null); 89 | setContentView(mReactRootView); 90 | 91 | mReactInstanceManager.removeReactInstanceEventListener(this); 92 | } 93 | }); 94 | 95 | if(MainApplication.getInstance().getIsLoad()){ 96 | ReactContext mContext = mReactInstanceManager.getCurrentReactContext(); 97 | CatalystInstance instance = mContext.getCatalystInstance(); 98 | 99 | loadForSystemOrAssets(instance,mContext); 100 | 101 | mReactRootView.startReactApplication(mReactInstanceManager, getResName(), null); 102 | setContentView(mReactRootView); 103 | 104 | } 105 | 106 | mReactInstanceManager.createReactContextInBackground(); 107 | return; 108 | } 109 | 110 | private void loadForSystemOrAssets ( CatalystInstance instance, ReactContext context ) { 111 | String filePath$Name = ""; 112 | // 是否有本地存储? 113 | Boolean hasCache = RNToolsManager.hasCache(getApplicationContext()); 114 | String basePhat = RNToolsManager.currentVersionByBundleName(getApplicationContext()).get("moduleType"); 115 | 116 | // 加载对应的 load 117 | if(hasCache){ 118 | filePath$Name = getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + "/Bundle/"+ basePhat + "/" + getJSBundleAssetName(); 119 | }else{ 120 | filePath$Name = "assets://" + getJSBundleAssetName(); 121 | } 122 | 123 | 124 | if(!hasCache) { 125 | // loadScriptFromAssets FromAssets 不再适用 126 | ((CatalystInstanceImpl)instance).loadScriptFromAssets(context.getAssets(),filePath$Name ,false); 127 | return; 128 | } 129 | 130 | ((CatalystInstanceImpl)instance).loadSplitBundleFromFile( filePath$Name, filePath$Name); 131 | 132 | } 133 | 134 | @Override 135 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 136 | super.onActivityResult(requestCode, resultCode, data); 137 | if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { 138 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 139 | if (!Settings.canDrawOverlays(this)) { 140 | // SYSTEM_ALERT_WINDOW permission not granted 141 | } 142 | } 143 | } 144 | mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data ); 145 | } 146 | 147 | @Override 148 | public void invokeDefaultOnBackPressed() { 149 | super.onBackPressed(); 150 | } 151 | 152 | @Override 153 | protected void onPause() { 154 | super.onPause(); 155 | 156 | if (mReactInstanceManager != null) { 157 | mReactInstanceManager.onHostPause(this); 158 | } 159 | } 160 | 161 | @Override 162 | protected void onResume() { 163 | super.onResume(); 164 | 165 | if (mReactInstanceManager != null) { 166 | mReactInstanceManager.onHostResume(this, this); 167 | } 168 | } 169 | 170 | @Override 171 | protected void onDestroy() { 172 | super.onDestroy(); 173 | 174 | if (mReactInstanceManager != null) { 175 | mReactInstanceManager.onHostDestroy(this); 176 | } 177 | if (mReactRootView != null) { 178 | mReactRootView.unmountReactApplication(); 179 | } 180 | } 181 | 182 | 183 | @Override 184 | public void onBackPressed() { 185 | if (mReactInstanceManager != null) { 186 | mReactInstanceManager.onBackPressed(); 187 | } else { 188 | super.onBackPressed(); 189 | } 190 | } 191 | 192 | @Override 193 | public boolean onKeyUp(int keyCode, KeyEvent event) { 194 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 195 | mReactInstanceManager.showDevOptionsDialog(); 196 | return true; 197 | } 198 | return super.onKeyUp(keyCode, event); 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/myapprnn/RNToolPackage.java: -------------------------------------------------------------------------------- 1 | package com.example.myapprnn; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.JavaScriptModule; 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.uimanager.ViewManager; 10 | 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | public class RNToolPackage implements ReactPackage { 16 | public RNToolsManager rnm; 17 | 18 | @NonNull 19 | @Override 20 | public List createNativeModules(ReactApplicationContext reactContext) { 21 | return Arrays.asList( new com.example.myapprnn.RNToolsManager(reactContext) ); 22 | } 23 | 24 | public List> createJSModules() { 25 | return Collections.emptyList(); 26 | } 27 | 28 | @NonNull 29 | @Override 30 | public List createViewManagers(ReactApplicationContext reactContext) { 31 | return Collections.emptyList(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/src_assets_imgs_bigimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-mdpi/src_assets_imgs_bigimage.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/src_assets_imgs_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-mdpi/src_assets_imgs_default.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/src_assets_imgs_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-mdpi/src_assets_imgs_test.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/src_modules_business1_assets_img_1024_500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-mdpi/src_modules_business1_assets_img_1024_500.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/src_modules_main_assets_img_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-mdpi/src_modules_main_assets_img_test.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/src_assets_imgs_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-xhdpi/src_assets_imgs_default.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/src_assets_imgs_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/drawable-xxhdpi/src_assets_imgs_default.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_bu1.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_bu2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | myappRNN 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /android/app/src/test/java/com/example/myapprnn/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.myapprnn; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '7.2.1' apply false 4 | id 'com.android.library' version '7.2.1' apply false 5 | } 6 | 7 | allprojects { 8 | } 9 | task clean(type: Delete) { 10 | delete rootProject.buildDir 11 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Enables namespacing of each library's R class so that its R class includes only the 19 | # resources declared in the library itself and none from the library's dependencies, 20 | # thereby reducing the size of the R class for that library 21 | android.nonTransitiveRClass=true 22 | MYAPP_RELEASE_STORE_FILE=my-release-key.keystore 23 | MYAPP_RELEASE_KEY_ALIAS=my-key-alias 24 | MYAPP_RELEASE_STORE_PASSWORD=123456 25 | MYAPP_RELEASE_KEY_PASSWORD=123456 -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Sep 16 10:58:34 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | // 注意这里 要去掉 请见一个 github 的issuss https://github.com/realm/realm-java/issues/7374 ,以及 7.0 下 gradle 的管理文档 10 | // repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 11 | repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) 12 | repositories { 13 | google() 14 | mavenCentral() 15 | maven { 16 | // All of React Native (JS, Android binaries) is installed from npm 17 | url("$rootDir/../node_modules/react-native/android") 18 | } 19 | maven { 20 | // Android JSC is installed from npm 21 | url("$rootDir/../node_modules/jsc-android/dist") 22 | } 23 | } 24 | } 25 | rootProject.name = "myappRNN" 26 | 27 | // 在新版本中 (@react-native-community/cli )它把 link 给删除了, 会自动进行link 不需要你手动加 28 | // 添加自动link 库 29 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); 30 | applyNativeModulesSettingsGradle(settings) 31 | include ':app' -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "name": "MyReactNativeApp" 4 | }, 5 | "bu1": { 6 | "name": "bu1" 7 | }, 8 | "bu2": { 9 | "name": "bu2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /base.js: -------------------------------------------------------------------------------- 1 | // 这里是存放 全模块的 通用 配置,它们会被打入 base 基础包中, 不要随意的添加! 这会让基础包变得越来越大 2 | import "react"; 3 | import { AppRegistry } from "react-native"; 4 | import "react-native-device-info"; 5 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | const clean = function (file) { 4 | fs.writeFileSync(file, JSON.stringify({})); 5 | }; 6 | 7 | const hasBuildInfo = function (file, path) { 8 | const cacheFile = require(file); 9 | return Boolean(cacheFile[path]); 10 | }; 11 | 12 | const writeBuildInfo = function (file, path, id) { 13 | const cacheFile = require(file); 14 | cacheFile[path] = id; 15 | fs.writeFileSync(file, JSON.stringify(cacheFile)); 16 | }; 17 | 18 | const getCacheFile = function (file, path) { 19 | const cacheFile = require(file); 20 | return cacheFile[path] || 0; 21 | }; 22 | 23 | const isPwdFile = (path) => { 24 | const cwd = __dirname.split("/").splice(-1, 1).toString(); 25 | 26 | const pathArray = path.split("/"); 27 | const map = new Map(); 28 | const reverseMap = new Map(); 29 | 30 | pathArray.forEach((it, indx) => { 31 | map.set(it, indx); 32 | reverseMap.set(indx, it); 33 | }); 34 | 35 | if (pathArray.length - 2 == map.get(cwd)) { 36 | return reverseMap.get(pathArray.length - 1).replace(/\.js/, ""); 37 | } 38 | 39 | return ""; 40 | }; 41 | 42 | module.exports = { 43 | hasBuildInfo, 44 | writeBuildInfo, 45 | getCacheFile, 46 | clean, 47 | isPwdFile, 48 | }; 49 | -------------------------------------------------------------------------------- /bundle/IOS.ios.bundle: -------------------------------------------------------------------------------- 1 | __d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) { 2 | var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0]); 3 | 4 | var _classCallCheck2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1])); 5 | 6 | var _createClass2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[2])); 7 | 8 | var _inherits2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[3])); 9 | 10 | var _possibleConstructorReturn2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[4])); 11 | 12 | var _getPrototypeOf2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[5])); 13 | 14 | var _react = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[6])); 15 | 16 | var _reactNative = _$$_REQUIRE(_dependencyMap[7]); 17 | 18 | var _native = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[8])); 19 | 20 | var _jsxRuntime = _$$_REQUIRE(_dependencyMap[9]); 21 | 22 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } 23 | 24 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } 25 | 26 | var changeActivity = _native.default.changeActivity; 27 | 28 | var RNHighScores = function (_React$Component) { 29 | (0, _inherits2.default)(RNHighScores, _React$Component); 30 | 31 | var _super = _createSuper(RNHighScores); 32 | 33 | function RNHighScores() { 34 | (0, _classCallCheck2.default)(this, RNHighScores); 35 | return _super.apply(this, arguments); 36 | } 37 | 38 | (0, _createClass2.default)(RNHighScores, [{ 39 | key: "render", 40 | value: function render() { 41 | return (0, _jsxRuntime.jsxs)(_reactNative.View, { 42 | style: styles.container, 43 | children: [(0, _jsxRuntime.jsx)(_reactNative.Text, { 44 | onPress: function onPress() { 45 | changeActivity("IOS2"); 46 | }, 47 | style: styles.highScoresTitle, 48 | children: "\u8FD4\u56DEIOS2" 49 | }), (0, _jsxRuntime.jsx)(_reactNative.View, { 50 | children: (0, _jsxRuntime.jsx)(_reactNative.Button, { 51 | title: "IOS" 52 | }) 53 | })] 54 | }); 55 | } 56 | }]); 57 | return RNHighScores; 58 | }(_react.default.Component); 59 | 60 | var styles = _reactNative.StyleSheet.create({ 61 | container: { 62 | flex: 1, 63 | justifyContent: 'center', 64 | alignItems: 'center', 65 | backgroundColor: '#FFFFFF' 66 | }, 67 | highScoresTitle: { 68 | fontSize: 20, 69 | textAlign: 'center', 70 | margin: 10 71 | }, 72 | scores: { 73 | textAlign: 'center', 74 | color: '#333333', 75 | marginBottom: 5 76 | } 77 | }); 78 | 79 | _reactNative.AppRegistry.registerComponent('IOS', function () { 80 | return RNHighScores; 81 | }); 82 | },40000000,[7,16,17,28,30,33,1,3,40000001,180]); 83 | __d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) { 84 | var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0]); 85 | 86 | Object.defineProperty(exports, "__esModule", { 87 | value: true 88 | }); 89 | exports.default = undefined; 90 | 91 | var _asyncToGenerator2 = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1])); 92 | 93 | var _reactNative = _$$_REQUIRE(_dependencyMap[2]); 94 | 95 | if (!_reactNative.NativeModules.RNToolsManager) { 96 | throw new Error("native模块加载失败"); 97 | } 98 | 99 | var RNToolsManager = { 100 | changeActivity: function changeActivity(value) { 101 | if (_reactNative.Platform.OS === 'ios') { 102 | return _reactNative.NativeModules.RNToolsManager.changeActivity("bundle/" + value + ".ios", value); 103 | } 104 | 105 | return _reactNative.NativeModules.RNToolsManager.changeActivity(value, null); 106 | }, 107 | writeFileFoRC: function writeFileFoRC(versionMapInfo) { 108 | return _reactNative.NativeModules.RNToolsManager.writeFileFoRC(versionMapInfo); 109 | }, 110 | cleanFileByPath: function cleanFileByPath() { 111 | return _reactNative.NativeModules.RNToolsManager.cleanFileByPath(); 112 | }, 113 | downloadFiles: function downloadFiles(url, type, module) { 114 | return _reactNative.NativeModules.RNToolsManager.downloadFiles(url, type, module); 115 | }, 116 | touchZip: function touchZip() { 117 | return _reactNative.NativeModules.RNToolsManager.touchZip(); 118 | }, 119 | getAndroidDEV: function () { 120 | var _getAndroidDEV = (0, _asyncToGenerator2.default)(function* () { 121 | return _reactNative.NativeModules.RNToolsManager.getAndroidDEV(); 122 | }); 123 | 124 | function getAndroidDEV() { 125 | return _getAndroidDEV.apply(this, arguments); 126 | } 127 | 128 | return getAndroidDEV; 129 | }(), 130 | isInited: function () { 131 | var _isInited = (0, _asyncToGenerator2.default)(function* () { 132 | return _reactNative.NativeModules.RNToolsManager.isInited(); 133 | }); 134 | 135 | function isInited() { 136 | return _isInited.apply(this, arguments); 137 | } 138 | 139 | return isInited; 140 | }(), 141 | getCurrentVersion: function () { 142 | var _getCurrentVersion = (0, _asyncToGenerator2.default)(function* (module, type) { 143 | return _reactNative.NativeModules.RNToolsManager.getCurrentVersion(module, type); 144 | }); 145 | 146 | function getCurrentVersion(_x, _x2) { 147 | return _getCurrentVersion.apply(this, arguments); 148 | } 149 | 150 | return getCurrentVersion; 151 | }(), 152 | setFileVersion: function () { 153 | var _setFileVersion = (0, _asyncToGenerator2.default)(function* (module, type, newVersion) { 154 | return _reactNative.NativeModules.RNToolsManager.setFileVersion(module, type, newVersion); 155 | }); 156 | 157 | function setFileVersion(_x3, _x4, _x5) { 158 | return _setFileVersion.apply(this, arguments); 159 | } 160 | 161 | return setFileVersion; 162 | }() 163 | }; 164 | var _default = RNToolsManager; 165 | exports.default = _default; 166 | },40000001,[7,269,3]); 167 | __r(21); 168 | __r(40000000); -------------------------------------------------------------------------------- /bundle/assets/src/modules/Business1/assets/img/1024_500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/bundle/assets/src/modules/Business1/assets/img/1024_500.png -------------------------------------------------------------------------------- /common.js: -------------------------------------------------------------------------------- 1 | // 这里是存放 全模块的 通用 配置,它们会被打入 base 基础包中, 不要随意的添加! 这会让基础包变得越来越大 2 | import "react"; 3 | import "react-native"; 4 | import "react-native-device-info"; 5 | 6 | console.log("init common -------->"); -------------------------------------------------------------------------------- /common/hooks/useServerHot.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { Platform, Alert, ToastAndroid } from 'react-native' 3 | import NativeModule from '../native' 4 | 5 | // url and config 6 | const useServerHot = ( props ) => { 7 | const { host, versionInfo } = props 8 | const [loading, setLoading] = useState(true); 9 | 10 | const getData = async (version, module, type, key) => { 11 | const value = await fetch( 12 | `${host}/api/version_info?oldVersion=${version}&pageModule=${module}&type=${type}&appKey=${versionInfo.key}&platform=${Platform.OS.toUpperCase()}` 13 | ); 14 | const data = await value.json(); 15 | return data; 16 | }; 17 | 18 | const CodePush = async () => { 19 | const UpperCaseType = versionInfo.isStaging ? "Staging" : "Release"; 20 | 21 | // 获取是否DEV 22 | const isDebug = await NativeModule.getAndroidDEV(); 23 | 24 | if (isDebug) { 25 | setLoading(false) 26 | return; 27 | } 28 | 29 | // 获取是否已经初始化到 cache 下 30 | const isInited = await NativeModule.isInited(); 31 | 32 | 33 | // 是否完成文件夹的创建 34 | if (!isInited) { 35 | // cv 文件夹 36 | await NativeModule.writeFileFoRC(JSON.stringify(versionInfo)); 37 | } 38 | 39 | // 遍历当前i模块是否是最新的版本 40 | const promiseAllVersionInfo = []; 41 | const keys = versionInfo.isStaging ? "staging" : "release"; 42 | Object.keys(versionInfo[keys]).forEach((it) => { 43 | promiseAllVersionInfo.push( 44 | NativeModule.getCurrentVersion( 45 | it, 46 | keys 47 | ) 48 | ); 49 | }); 50 | 51 | 52 | const promiseAllIsLoadUpdate = []; 53 | Promise.all(promiseAllVersionInfo).then(res => { 54 | res.forEach((it) => { 55 | promiseAllIsLoadUpdate.push(getData(it.version, it.module, UpperCaseType , it.key, )); 56 | }); 57 | // 58 | hasNewVersion() 59 | }) 60 | 61 | const hasNewVersion = () => { 62 | // 更新和download 指定的版本 63 | Promise.all(promiseAllIsLoadUpdate).then((res) => { 64 | // 看看返回的数据 如果需要更新 就更新 并且重新写入新的数据 65 | const value = res 66 | .filter((data) => data.data?.isNeedRefresh) 67 | .map((r) => r.data); 68 | 69 | // 只有有一个人 isNeedRefresh = true 请弹窗 提示更新 70 | if (res.some((it) => it.data.isNeedRefresh)) { 71 | Alert.alert("有版本更新", "", [ 72 | { 73 | text: "更新", 74 | onPress: updateVersion(value), 75 | }, 76 | ]); 77 | }else{ 78 | setLoading(false) 79 | } 80 | 81 | }); 82 | } 83 | 84 | 85 | }; 86 | 87 | 88 | // 更新成功 写入 正确的 最新的版本信息 89 | const updateVersion = value => { 90 | return () => { 91 | const type = versionInfo.isStaging ? "staging" : "release"; 92 | 93 | const allDownloadTask = []; 94 | value.forEach((it) => { 95 | allDownloadTask.push( 96 | NativeModule.downloadFiles( 97 | `${host}${it.downloadPathL}`, 98 | type, 99 | it.module 100 | ) 101 | ); 102 | }); 103 | 104 | // 有多少更新 就重写多少次 105 | Promise.all(allDownloadTask).then(() => { 106 | value.forEach((it) => { 107 | NativeModule.setFileVersion(it.module, type , it.newVersion); 108 | }); 109 | 110 | setTimeout(()=>{ 111 | setLoading(false) 112 | ToastAndroid.show('更新成功 请重启应用', 1500) 113 | },2000) 114 | }); 115 | } 116 | }; 117 | 118 | return { 119 | CodePush, 120 | loading 121 | } 122 | } 123 | 124 | export default useServerHot -------------------------------------------------------------------------------- /common/index.js: -------------------------------------------------------------------------------- 1 | // 这里是存放 全模块的 通用 配置,它们会被打入 base 基础包中, 不要随意的添加! 这会让基础包变得越来越大 2 | import "react"; 3 | import "react-native"; 4 | import "react-native-device-info"; 5 | 6 | -------------------------------------------------------------------------------- /common/native/index.js: -------------------------------------------------------------------------------- 1 | import { NativeModules, Platform } from "react-native"; 2 | 3 | if (!NativeModules.RNToolsManager) { 4 | throw new Error("native模块加载失败"); 5 | } 6 | 7 | const RNToolsManager = { 8 | changeActivity: (value) => { 9 | // 此处可以优化 把名字全部统一,只需要确定一个规则 path 为 [moduleName].[platform].bundle 10 | // 比如 common.ios.bundle, IO2.ios.bundle, common.android.bundle, IO2.android.bundle, 11 | // 参数只需要 传递 IO2 就好了这个IOS2 应该和模块的 registerComponent name 保持一致! 12 | if(Platform.OS === 'ios') { 13 | return NativeModules.RNToolsManager.changeActivity(`bundle/${value}.ios`, value); 14 | } 15 | return NativeModules.RNToolsManager.changeActivity(value, null); 16 | }, 17 | writeFileFoRC: (versionMapInfo) => { 18 | return NativeModules.RNToolsManager.writeFileFoRC(versionMapInfo); 19 | }, 20 | cleanFileByPath: () => { 21 | return NativeModules.RNToolsManager.cleanFileByPath(); 22 | }, 23 | downloadFiles: (url, type, module) => { 24 | return NativeModules.RNToolsManager.downloadFiles(url, type, module); 25 | }, 26 | touchZip: () => { 27 | return NativeModules.RNToolsManager.touchZip(); 28 | }, 29 | getAndroidDEV: async () => { 30 | return NativeModules.RNToolsManager.getAndroidDEV(); 31 | }, 32 | isInited: async () => { 33 | return NativeModules.RNToolsManager.isInited(); 34 | }, 35 | getCurrentVersion: async (module, type) => { 36 | return NativeModules.RNToolsManager.getCurrentVersion(module, type); 37 | }, 38 | setFileVersion: async (module, type, newVersion) => { 39 | return NativeModules.RNToolsManager.setFileVersion( 40 | module, 41 | type, 42 | newVersion 43 | ); 44 | }, 45 | }; 46 | 47 | export default RNToolsManager; 48 | -------------------------------------------------------------------------------- /common/utils/index.js: -------------------------------------------------------------------------------- 1 | import storageApp from './storage.js' 2 | import * as navigation from './navigation.js' 3 | 4 | export { 5 | storageApp, 6 | navigation 7 | } -------------------------------------------------------------------------------- /common/utils/navigation.js: -------------------------------------------------------------------------------- 1 | import storageApp from './storage'; 2 | import RNToolsManager from '../native'; 3 | 4 | const pushToActivity = (activity, params) => { 5 | storageApp.save({ 6 | key:"MessageActivity", 7 | data: params, 8 | expires: 1000 * 3600 9 | }) 10 | 11 | const _pre_fix = "com.example.myapprnn."; 12 | RNToolsManager.changeActivity(_pre_fix + activity); 13 | } 14 | 15 | const getFromActivity = () => { 16 | return new Promise((resolve, reject) => { 17 | storageApp.load({ 18 | key:"MessageActivity", 19 | autoSync:true, 20 | }).then((data) => { 21 | 22 | resolve(data) 23 | 24 | }).catch(() => { 25 | 26 | reject("error") 27 | 28 | }).finally(() => { 29 | 30 | }) 31 | 32 | }) 33 | } 34 | 35 | export { 36 | pushToActivity, 37 | getFromActivity 38 | } -------------------------------------------------------------------------------- /common/utils/storage.js: -------------------------------------------------------------------------------- 1 | import { AsyncStorage } from 'react-native' 2 | import Storage from 'react-native-storage' 3 | 4 | const storageApp = new Storage({ 5 | size:1000, 6 | storageBackend: AsyncStorage, 7 | defaultExpires: 1000 * 3600 * 24, 8 | enableCache: true 9 | }) 10 | 11 | export default storageApp -------------------------------------------------------------------------------- /config/ModuleIdConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "index.js": 100000, 3 | "Bu1.js": 200000, 4 | "Bu2.js": 300000 5 | } 6 | -------------------------------------------------------------------------------- /config/bundleBuInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": 10000000, 3 | "Bu1": 20000000, 4 | "Bu2": 30000000, 5 | "IOS": 40000000, 6 | "IOS2": 50000000 7 | } 8 | -------------------------------------------------------------------------------- /config/getModuleIdByIndex.json: -------------------------------------------------------------------------------- 1 | { 2 | "index.js": 100000, 3 | "Bu1.js": 200000, 4 | "Bu2.js": 300000 5 | } 6 | -------------------------------------------------------------------------------- /config/platformMap.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/config/platformMap.json -------------------------------------------------------------------------------- /config/platformNameMap.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/config/platformNameMap.json -------------------------------------------------------------------------------- /config/versionMap.json: -------------------------------------------------------------------------------- 1 | { 2 | "staging": { 3 | "bu1.android.bundle": "1.0.0", 4 | "bu2.android.bundle": "1.0.0", 5 | "index.android.bundle": "1.0.0" 6 | }, 7 | "release": { 8 | "bu1.android.bundle": "1.0.0", 9 | "bu2.android.bundle": "1.0.0", 10 | "index.android.bundle": "1.0.0" 11 | }, 12 | "key": "AAAA", 13 | "isStaging": true 14 | } 15 | -------------------------------------------------------------------------------- /doc/ServiceHot设计.drawio: -------------------------------------------------------------------------------- 1 | 7V1bc6s4Ev41VO0+JAWIi3gEXzJn55yd7KR2Z/I0hUG2mWDLA/jEPr9+JSFsQHLsJJhLMlWpBIS4qfvr/rpbIgoYrXZ3ib9ZfsMhihVdDXcKGCu6rmnQIn9oyz5vgUDNGxZJFPJOx4aH6AfijUW3bRSitNIxwzjOok21McDrNQqySpufJPi52m2O4+pdN/4CCQ0PgR+Lrb9FYbbkb6Hbx/afULRYFnfWLCc/svKLzvxN0qUf4udSE5goYJRgnOVbq90IxXTwinHJz5ueOHp4sASts0tO8Jar+R349Zd4ff9l4/7n5umn6OsN0PnDZfvijVFIBoDv4iRb4gVe+/Hk2OoleLsOEb2sSvaOfb5ivCGNGmn8E2XZnkvT32aYNC2zVcyPol2U/V7afqSXujX53njHr8x29nwnfUJZsOQnie/OhyPF2yRAL7wwV8fMTxYoe6GfxgeGjkbpDnxo7xBeoSzZkw4Jiv0s+l5VF59r3eLQ7ygYssFl8xo5ca367sdbfqvZNiK6LJPeV39GUFgZcT+OFmuyHZABQwlp+I6SLCJq7vIDqygMc+GiNPrhz9j16LhvcLTO2OuYnmKOz0viRT2jt0U7RYJcfssKOCoDzc9Sb1Xg8FO5TbnhF79YFPzi9/TVSl3wfJ4SpajL6vAMbxefJUhPmZiKN1KgSjdcW4GeKMo4JlaOyuR5GWXoYeMzzX4mhrYm3HSTm755tKOw9OZRHI9wjBN2IRCaCIYGlVyW4CdUOgL1GbCsi9ElSO+klDTVrIgIciP4fLShBm9alsxn0dY4fuDLAoBThejUBNJdaAqSIKZ7Qze3q9gNMlzGD8PaPU6jLMIURzOcZXglAViGa1LD2yyO1kQaheO63MpdLge9KgZbFAOQiMG6lhg0TZCDe3+vTGzFMRQXKhNLgVDx7I8rAc3pWAQAfDKPX3jy8y4f9Mvly52GO1YcyGyWzhBjMsQwK+Y5ige4OfNUqZj7SA1AU9TgRr0Fqg0reHsnNShArMsuen3eUOhuSQe8/375OmZCHjFXRYbEo7+JDYUO1QViQ52R4o6UiaF4U8XVmFXVFHcqaEQV1mdYRo1UzOfICgIZqQhtZ6ZexZRqZ72ZprdqS0Wq0FNbSgY92f9e3imdRXePp7G9pm0wuNAGA61XNrh47jpvrBpaAj3PUxyHIW6suCpDnKM4eZ8JJfe0D0GlQ5+HX8Fi/SGlPtIrkN/QpqTUnXADT/DuWQQvKWU6IrwnU8ZoRxU34bn0OQaOfAP0DPlFoFJSjH93aQuO+H8sHTlnC47wf6yg/7q2wG4a4id8tl3VGaDXlCE3Rvys5n23IcY6j8xRM9DDcSXqcTzFM9iGxbHu6AzJeWev5PD/djivULKzDsdonPTLtdGocReayAKaCgwDEkWFlg7bVU6RWD4OJWAwTrmPN+QSdQ3aFblo74sXWggJbAklIWQBsFQWMSCEE5jM8Y8LAuJwa1OPDyxKEVzGRxxVcQs+Qq8DKfUgFkngDUu8mm3T13MGGCA5Z5hB0zCvEi3UOIMmyUFCCWeAV+MM1lCMd0NGuHC4HRjhdwlKF8mdMnEoIuC4AMuU5i0Hzqrr8bRhdE2rgciZitgIMHs1pvZNQNGACyWW2a9CiamJw9tPI9UxwwSXMszm4533QUzGHz5VLVJXO8aYIcsqfWgrZ9ajn85F0Gkg/ZpsTUPmyjAuNFeFv++JuTJlXOyipEgfI1fzBHDeVOoCRV63mdC1uHJ1bg2onn+9uNaAwyMet9Cqcg/HMs6wD7Z3j5KIjBdVwU4wbvSLkhji5DaagfCmrDRi0uSoM2EkRVXIiNOKCCt5SPKmtuK4CjRk2Y5SAEcu4jiyAK6vdqOYvtSE3dCc2pSU906fKzKcauWqtXzmFQ2HIfcQE8qjaG1sTAtoFyXExII5eaTyBDGHTRDTKol6uQcaeCoAgK5TAYYsTnGopPL8JDMB7mbzM9ozGZVqn7x0Uk9vPmT+Ilovqr0NSrvzhCmRMXQvUpS6sMkgZ9ezGNRrpbkD0wSlWOM1qmkQb2o8jII1Di+ZyXYozJZVBDSgIvr/vm0ef1bD0ZP+h+7PofbXL99vZGEUQaXJEGrTyhrliBZTFf3oNs5L79IhvlzKMgNQNRGNi6secQnCslqV1QdOfktfWNdFMiYfmc6mvMgfRyRj8pkN3fKkF5WsEZ6kGwWz6OMyA+n7S2alyKu6HyLP8SLsrj67RLWqdLeeqmqugP/ie5ZEvfTTkR8s0fQLkWLOcCRpxAFVcDWrOsaWhHFcq4IrH3SRkw4GX+3N+pIPXVvzbIxq/sqxW8alZKWRbsWUYKYbf11RFeuvLV386c3xOrvJGb5LOmj6ZsfGWp35wdOCactNkOONHk8Ws3/oNCVAg1OdJk/Yhqn+k51VXJVsLdhfmkoZ0598Bqlr/opi5KeoeC7ynvmj8f6fjKe1pJhmbdEidFpWTHm0VJ8BxFsOsfJwvYeh1gbc7Nh7AHFZ28eGVhHZnA+BGidt7xOUOAslSJCfIUavREy8K9U310+k+qyZZV6jFgtAlVXZ2mW4aKIWu//zj93+brJauuH9N/jb7sf4X96NmJF5LSyWRC7bBN3RwR4bTXIq9UWclDhVrRCkQniGV0kLQZQJTP1VFNNebhJQXQpIXKyr5ImJJFhQTTs9FNhbZtmGHDcpMzCJGOgv2iG9XWC8IH5+E6W3AV6xA0HKuk7n+S3IZuUmpu7Vb8PTjvnbhS79oAaVyQatmc76yaFLXvgKy7u5gTi8IwUF9SlgTMeGuzv5QYnO12zDGy3SpUmZPLx6Lwkg4+XvSx14luM0eXXqAY9dQ1d+xUaJweHTDEdr56dDN3KG2Z2Rk6dmxNW8gwkdG6IDxeyHtlMzmqq2S7WNz0b02pJs/cMvbcdQhhjcDyY3fqinNrFqpvjIVXWSUI8T46YgOFYPnNJvjdCaocYqhBZdrHsoBrvktfIpJSO+gpdvHKLmejlaMiNlwAF0Pf3aeQBtdvrpkgElW4sJVdf3tPC2tshKbTnfaopr1HqqEw3JtgBhB7LVWq5xWZ1OCW0C71o7eDcla1HkI9qvRJspm+NVr1acTEUPLCLVqt7UkXzDolgL1kpEag0mSukaXXCg6JJ99FBSC2SlwGGDy6rXejoH19/fh3kz3JwL4ab3C26W9Hsvw7awfRN58xb2RCJer9oTq+UMYjEglVkkHyeTYFodZxIKPfo8K3DtGv20W1yBKxWBLebGemocGzJyVktJGc3q1nZZEtv1sT8wUKtKmC1+w0M6oUKc6RVjPyQt84ROBFC/kbtgQQK9XMRUmoSgXzxB4oT8JFI+Ha0XC2EKmco+jdNQAZnsHv8LSI7C4/9SAZP/Aw== -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AppRegistry } from "react-native"; 3 | import Main from "./src/modules/Main"; 4 | import { main } from "./app.json"; 5 | // 整个App 的骨架,基础包 更新要严格控制 6 | 7 | AppRegistry.registerComponent(main.name, () => Main); 8 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | require_relative '../node_modules/react-native/scripts/react_native_pods' 3 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 4 | 5 | install! 'cocoapods', :deterministic_uuids => false 6 | platform :ios, '12.4' 7 | 8 | target 'myrnapp' do 9 | # Comment the next line if you don't want to use dynamic frameworks 10 | use_frameworks! :linkage => :static 11 | # 使用静态库 连接 不要使用动态库 或者 默认的连接 ,会有问题 12 | 13 | config = use_native_modules! 14 | flags = get_default_flags() 15 | 16 | pod 'RNDeviceInfo', path: '../node_modules/react-native-device-info' 17 | 18 | use_react_native!( 19 | :path => config[:reactNativePath], 20 | # Hermes is now enabled by default. Disable by setting this flag to false. 21 | # Upcoming versions of React Native may rely on get_default_flags(), but 22 | # we make it explicit here to aid in the React Native upgrade process. 23 | :hermes_enabled => false, 24 | :fabric_enabled => flags[:fabric_enabled], 25 | # Enables Flipper. 26 | # 27 | # Note that if you have use_frameworks! enabled, Flipper will not work and 28 | # you should disable the next line. 29 | # :flipper_configuration => FlipperConfiguration.enabled, 30 | # An absolute path to your application root. 31 | :app_path => "#{Pod::Config.instance.installation_root}/.." 32 | ) 33 | 34 | # Pods for myrnapp 35 | target 'myrnappTests' do 36 | inherit! :search_paths 37 | # Pods for testing 38 | end 39 | 40 | target 'myrnappUITests' do 41 | # Pods for testing 42 | end 43 | 44 | post_install do |installer| 45 | react_native_post_install( 46 | installer, 47 | # Set `mac_catalyst_enabled` to `true` in order to apply patches 48 | # necessary for Mac Catalyst builds 49 | :mac_catalyst_enabled => true 50 | ) 51 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /ios/myrnapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/myrnapp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/myrnapp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/myrnapp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/myrnapp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (readonly, strong) NSPersistentContainer *persistentContainer; 15 | @property (nonatomic, strong) UIWindow * window; 16 | 17 | - (void)saveContext; 18 | 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /ios/myrnapp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | #import "ViewController.h" 10 | @interface AppDelegate () 11 | 12 | @end 13 | 14 | @implementation AppDelegate 15 | 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 18 | // Override point for customization after application launch. 19 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 20 | self.window.backgroundColor = [UIColor whiteColor]; 21 | self.window.rootViewController = [[ViewController alloc] init];; 22 | [self.window makeKeyAndVisible]; 23 | 24 | return YES; 25 | } 26 | 27 | 28 | #pragma mark - Core Data stack 29 | 30 | @synthesize persistentContainer = _persistentContainer; 31 | 32 | - (NSPersistentContainer *)persistentContainer { 33 | // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it. 34 | @synchronized (self) { 35 | if (_persistentContainer == nil) { 36 | _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"myrnapp"]; 37 | [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) { 38 | if (error != nil) { 39 | // Replace this implementation with code to handle the error appropriately. 40 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 41 | 42 | /* 43 | Typical reasons for an error here include: 44 | * The parent directory does not exist, cannot be created, or disallows writing. 45 | * The persistent store is not accessible, due to permissions or data protection when the device is locked. 46 | * The device is out of space. 47 | * The store could not be migrated to the current model version. 48 | Check the error message to determine what the actual problem was. 49 | */ 50 | NSLog(@"Unresolved error %@, %@", error, error.userInfo); 51 | abort(); 52 | } 53 | }]; 54 | } 55 | } 56 | 57 | return _persistentContainer; 58 | } 59 | 60 | #pragma mark - Core Data Saving support 61 | 62 | - (void)saveContext { 63 | NSManagedObjectContext *context = self.persistentContainer.viewContext; 64 | NSError *error = nil; 65 | if ([context hasChanges] && ![context save:&error]) { 66 | // Replace this implementation with code to handle the error appropriately. 67 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 68 | NSLog(@"Unresolved error %@, %@", error, error.userInfo); 69 | abort(); 70 | } 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /ios/myrnapp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/myrnapp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ios/myrnapp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/myrnapp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ios/myrnapp/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/myrnapp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSExceptionDomains 26 | 27 | localhost 28 | 29 | NSTemporaryExceptionAllowsInsecureHTTPLoads 30 | 31 | 32 | 33 | 34 | UIApplicationSupportsIndirectInputEvents 35 | 36 | UILaunchStoryboardName 37 | LaunchScreen 38 | UIRequiredDeviceCapabilities 39 | 40 | armv7 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ios/myrnapp/RNToolPackage.h: -------------------------------------------------------------------------------- 1 | // 2 | // RNToolPackage.h 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/10. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface RNToolPackage : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /ios/myrnapp/RNToolPackage.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNToolPackage.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/10. 6 | // 7 | 8 | #import "RNToolPackage.h" 9 | 10 | @implementation RNToolPackage 11 | 12 | RCT_EXPORT_MODULE(RNToolsManager) 13 | 14 | // 最简单的一个方法 变更多个bundle 15 | RCT_REMAP_METHOD(changeActivity, 16 | changeActivityWithA:( NSString *)bundlePath bunldeName:( NSString*)bunldeName 17 | ){ 18 | 19 | // 重新设置一个rootView 20 | dispatch_async(dispatch_get_main_queue(),^{ 21 | [[NSNotificationCenter defaultCenter] postNotificationName:@"changeBunle" object:@{ 22 | @"bundlePath":bundlePath, 23 | @"bunldeName":bunldeName, 24 | }]; 25 | }); 26 | 27 | }; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ios/myrnapp/ReactController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReactController.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/10. 6 | // 7 | 8 | #import 9 | #import "ViewController.h" 10 | 11 | @interface ReactController : NSObject 12 | +(void)setBridge:(RCTBridge*) bridge; 13 | +(RCTBridge*)getBridge; 14 | @end 15 | 16 | static RCTBridge *rctBridge = nil; 17 | 18 | @implementation ReactController 19 | 20 | + (void)setBridge:(RCTBridge*)bridge{ 21 | rctBridge = bridge; 22 | }; 23 | 24 | +(RCTBridge*)getBridge{ 25 | return rctBridge; 26 | }; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ios/myrnapp/SceneDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.h 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | 10 | @interface SceneDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow * window; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ios/myrnapp/SceneDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import "SceneDelegate.h" 9 | #import "AppDelegate.h" 10 | 11 | @interface SceneDelegate () 12 | 13 | @end 14 | 15 | @implementation SceneDelegate 16 | 17 | 18 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 19 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 20 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 21 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 22 | UIWindowScene *windowScene = (UIWindowScene *)scene; 23 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 24 | self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; 25 | [self.window setWindowScene:windowScene]; 26 | [self.window setBackgroundColor:[UIColor whiteColor]]; 27 | [self.window setRootViewController:[UITabBarController new]]; 28 | 29 | [self.window makeKeyAndVisible]; 30 | 31 | 32 | } 33 | 34 | 35 | - (void)sceneDidDisconnect:(UIScene *)scene { 36 | // Called as the scene is being released by the system. 37 | // This occurs shortly after the scene enters the background, or when its session is discarded. 38 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 39 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 40 | } 41 | 42 | 43 | - (void)sceneDidBecomeActive:(UIScene *)scene { 44 | // Called when the scene has moved from an inactive state to an active state. 45 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 46 | } 47 | 48 | 49 | - (void)sceneWillResignActive:(UIScene *)scene { 50 | // Called when the scene will move from an active state to an inactive state. 51 | // This may occur due to temporary interruptions (ex. an incoming phone call). 52 | } 53 | 54 | 55 | - (void)sceneWillEnterForeground:(UIScene *)scene { 56 | // Called as the scene transitions from the background to the foreground. 57 | // Use this method to undo the changes made on entering the background. 58 | } 59 | 60 | 61 | - (void)sceneDidEnterBackground:(UIScene *)scene { 62 | // Called as the scene transitions from the foreground to the background. 63 | // Use this method to save data, release shared resources, and store enough scene-specific state information 64 | // to restore the scene back to its current state. 65 | 66 | // Save changes in the application's managed object context when the application transitions to the background. 67 | [(AppDelegate *)UIApplication.sharedApplication.delegate saveContext]; 68 | } 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /ios/myrnapp/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @interface RCTBridge (PackageBundle) 12 | 13 | - (RCTBridge *)batchedBridge; 14 | - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync; 15 | 16 | @end 17 | 18 | @interface ViewController : UIViewController 19 | 20 | @property (nonatomic, strong) RCTBridge *bridge; 21 | @property (nonatomic, strong) UIViewController *vc1; 22 | @property (nonatomic, strong) UIViewController *vc2; 23 | -(void) loadScript:(NSString *)bundlePath bunldeName: (NSString *)bunldeName; 24 | 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /ios/myrnapp/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import "ViewController.h" 9 | #import 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | 18 | -(instancetype) init { 19 | self = [super init]; 20 | [self initBridge]; 21 | [self addObservers]; 22 | return self; 23 | }; 24 | 25 | - (void) initBridge { 26 | if(!self.bridge) { 27 | NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/common.ios" withExtension:@"bundle"]; 28 | // 初始化 bridge,并且加载主包 29 | self.bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation moduleProvider:nil launchOptions:nil]; 30 | } 31 | }; 32 | 33 | - (void) viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | // 加一些oc 的code 确保项目上正常的状态 37 | UIView *view = [[UIView alloc] init]; 38 | view.backgroundColor = [UIColor redColor]; 39 | view.frame = CGRectMake(100,100, 100, 100); 40 | [self.view addSubview:view]; 41 | 42 | view.userInteractionEnabled = YES; 43 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadScriptWithBridge)]; 44 | [view addGestureRecognizer:tap]; 45 | 46 | UIView *view2 = [[UIView alloc] init]; 47 | view2.backgroundColor = [UIColor greenColor]; 48 | view2.frame = CGRectMake(150,300, 100, 100); 49 | [self.view addSubview:view2]; 50 | 51 | view2.userInteractionEnabled = YES; 52 | UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openRNView2)]; 53 | [view2 addGestureRecognizer:tap2]; 54 | 55 | // 直接开始集成 56 | } 57 | 58 | - (void) testClick { 59 | NSLog(@"6666666"); 60 | } 61 | 62 | - (void)openRNView { 63 | NSLog(@"High Score Button Pressed"); 64 | NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8082/IOS.bundle?platform=ios"]; 65 | 66 | RCTRootView *rootView = 67 | [[RCTRootView alloc] initWithBundleURL: jsCodeLocation 68 | moduleName: @"RNHighScores" 69 | initialProperties: nil 70 | launchOptions: nil]; 71 | UIViewController *vc = [[UIViewController alloc] init]; 72 | vc.view = rootView; 73 | [self presentViewController:vc animated:YES completion:nil]; 74 | } 75 | 76 | - (void)openRNView2 { 77 | 78 | // NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8082/IOS2.bundle?platform=ios"]; 79 | NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/IOS2.ios" withExtension:@"bundle"]; 80 | 81 | 82 | RCTRootView *rootView = [[RCTRootView alloc] 83 | initWithBundleURL:jsCodeLocation 84 | moduleName:@"RNHighScores2" 85 | initialProperties:nil 86 | launchOptions:nil ]; 87 | 88 | UIViewController *vc = [[UIViewController alloc] init]; 89 | vc.view = rootView; 90 | [self presentViewController:vc animated:YES completion:nil]; 91 | }; 92 | 93 | // 设它为 IOS2 main 模块 94 | - (void)loadScriptWithBridge { 95 | [self loadScript:@"bundle/IOS2.ios" bunldeName:@"IOS2"]; 96 | }; 97 | 98 | - (void)changeView:(NSNotification *)notif{ 99 | 100 | 101 | NSString *bundlePath = @""; 102 | NSString *bunldeName = @""; 103 | bundlePath = [notif.object valueForKey:@"bundlePath"]; 104 | bunldeName = [notif.object valueForKey:@"bunldeName"]; 105 | 106 | // [self dismissViewControllerAnimated:YES completion:nil]; 107 | 108 | // 重制 原先的bridge 要不然会有问题 109 | // NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/common.ios" withExtension:@"bundle"]; 110 | // 111 | // self.bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation moduleProvider:nil launchOptions:nil]; 112 | 113 | [self loadScript:bundlePath bunldeName:bunldeName]; 114 | }; 115 | 116 | 117 | - (void)addObservers { 118 | // 监听通知 119 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeView:) name:@"changeBunle" object:nil]; 120 | }; 121 | 122 | - (void)removeObservers { 123 | // 监听通知 124 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 125 | }; 126 | 127 | - (void)dealloc { 128 | [self removeObservers]; 129 | }; 130 | 131 | -(void) loadScript:(NSString *)bundlePath bunldeName: (NSString *)bunldeName { 132 | 133 | NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:bundlePath withExtension:@"bundle"]; 134 | 135 | if(self.bridge) { 136 | NSError *error = nil; 137 | NSData *sourceBuz = [NSData dataWithContentsOfFile:jsCodeLocation.path 138 | options:NSDataReadingMappedIfSafe 139 | error:&error]; 140 | 141 | [self.bridge.batchedBridge executeSourceCode:sourceBuz sync:NO]; 142 | 143 | RCTRootView *rootView = 144 | [[RCTRootView alloc] initWithBridge:self.bridge moduleName:bunldeName initialProperties:nil]; 145 | UIViewController *vc = [[UIViewController alloc] init]; 146 | 147 | // [self setView: rootView]; 148 | // 第一次的时候没有 添加 149 | if(self.vc1 == nil) { 150 | vc.view = rootView; 151 | [self presentViewController:vc animated:YES completion:nil]; 152 | self.vc1 = vc; 153 | return; 154 | } 155 | 156 | // 第二次的时候 从第一次上面再此添加 157 | vc.view = rootView; 158 | self.vc2 = vc; 159 | [self.vc1 presentViewController: self.vc2 animated:YES completion:nil]; 160 | 161 | }; 162 | } 163 | @end 164 | -------------------------------------------------------------------------------- /ios/myrnapp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // myrnapp 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) { 12 | NSString * appDelegateClassName; 13 | @autoreleasepool { 14 | // Setup code that might create autoreleased objects goes here. 15 | appDelegateClassName = NSStringFromClass([AppDelegate class]); 16 | } 17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 18 | } 19 | -------------------------------------------------------------------------------- /ios/myrnapp/myrnapp.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | myrnapp.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/myrnapp/myrnapp.xcdatamodeld/myrnapp.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ios/myrnappTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/myrnappTests/myrnappTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // myrnappTests.m 3 | // myrnappTests 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | 10 | @interface myrnappTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation myrnappTests 15 | 16 | - (void)setUp { 17 | // Put setup code here. This method is called before the invocation of each test method in the class. 18 | } 19 | 20 | - (void)tearDown { 21 | // Put teardown code here. This method is called after the invocation of each test method in the class. 22 | } 23 | 24 | - (void)testExample { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | - (void)testPerformanceExample { 30 | // This is an example of a performance test case. 31 | [self measureBlock:^{ 32 | // Put the code you want to measure the time of here. 33 | }]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /ios/myrnappUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/myrnappUITests/myrnappUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // myrnappUITests.m 3 | // myrnappUITests 4 | // 5 | // Created by 李仕增 on 2022/10/8. 6 | // 7 | 8 | #import 9 | 10 | @interface myrnappUITests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation myrnappUITests 15 | 16 | - (void)setUp { 17 | // Put setup code here. This method is called before the invocation of each test method in the class. 18 | 19 | // In UI tests it is usually best to stop immediately when a failure occurs. 20 | self.continueAfterFailure = NO; 21 | 22 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 23 | } 24 | 25 | - (void)tearDown { 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | } 28 | 29 | - (void)testExample { 30 | // UI tests must launch the application that they test. 31 | XCUIApplication *app = [[XCUIApplication alloc] init]; 32 | [app launch]; 33 | 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | - (void)testLaunchPerformance { 39 | if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { 40 | // This measures how long it takes to launch your application. 41 | [self measureWithMetrics:@[[[XCTApplicationLaunchMetric alloc] init]] block:^{ 42 | [[[XCUIApplication alloc] init] launch]; 43 | }]; 44 | } 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /metro.base.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { hasBuildInfo, writeBuildInfo } = require("./utils"); 3 | 4 | 5 | function createModuleIdFactory() { 6 | const fileToIdMap = new Map(); 7 | let nextId = 0; 8 | 9 | // 如果是业务 模块请以 10000000 来自增命名 10 | return (path) => { 11 | let id = fileToIdMap.get(path); 12 | 13 | if (typeof id !== "number") { 14 | id = nextId++; 15 | fileToIdMap.set(path, id); 16 | 17 | !hasBuildInfo(path) && writeBuildInfo(path, fileToIdMap.get(path)); 18 | } 19 | 20 | return id; 21 | }; 22 | } 23 | 24 | module.exports = { 25 | serializer: { 26 | createModuleIdFactory: createModuleIdFactory, // 给 bundle 一个id 避免冲突 cli 源码中这个id 是从1 开始 自增的 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /metro.common.config.js: -------------------------------------------------------------------------------- 1 | const { hasBuildInfo, writeBuildInfo, clean } = require("./build"); 2 | 3 | function createModuleIdFactory() { 4 | const fileToIdMap = new Map(); 5 | let nextId = 0; 6 | clean("./config/bundleCommonInfo.json"); 7 | 8 | // 如果是业务 模块请以 10000000 来自增命名 9 | return (path) => { 10 | let id = fileToIdMap.get(path); 11 | 12 | if (typeof id !== "number") { 13 | id = nextId++; 14 | fileToIdMap.set(path, id); 15 | 16 | !hasBuildInfo("./config/bundleCommonInfo.json", path) && 17 | writeBuildInfo( 18 | "./config/bundleCommonInfo.json", 19 | path, 20 | fileToIdMap.get(path) 21 | ); 22 | } 23 | 24 | return id; 25 | }; 26 | } 27 | 28 | module.exports = { 29 | serializer: { 30 | createModuleIdFactory: createModuleIdFactory, // 给 bundle 一个id 避免冲突 cli 源码中这个id 是从1 开始 自增的 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /metro.main.config.js: -------------------------------------------------------------------------------- 1 | const { hasBuildInfo, getCacheFile, isPwdFile } = require("./build"); 2 | const bundleBuInfo = require("./config/bundleBuInfo.json"); 3 | function postProcessModulesFilter(module) { 4 | if ( 5 | module["path"].indexOf("__prelude__") >= 0 || 6 | module["path"].indexOf("polyfills") >= 0 7 | ) { 8 | return false; 9 | } 10 | 11 | if (hasBuildInfo("./config/bundleCommonInfo.json", module.path)) { 12 | return false; 13 | } 14 | 15 | return true; 16 | } 17 | 18 | // 不要使用 string 会导致 bundle 体积陡增 19 | function createModuleIdFactory() { 20 | // 如果是业务 模块请以 10000000 来自增命名 21 | const fileToIdMap = new Map(); 22 | let nextId = 10000000; 23 | let isFirst = false; 24 | 25 | return (path) => { 26 | if (Boolean(getCacheFile("./config/bundleCommonInfo.json", path))) { 27 | return getCacheFile("./config/bundleCommonInfo.json", path); 28 | } 29 | 30 | if (!isFirst && isPwdFile(path)) { 31 | nextId = bundleBuInfo[isPwdFile(path)]; 32 | isFirst = true; 33 | } 34 | 35 | let id = fileToIdMap.get(path); 36 | if (typeof id !== "number") { 37 | id = nextId++; 38 | fileToIdMap.set(path, id); 39 | } 40 | return id; 41 | }; 42 | } 43 | 44 | module.exports = { 45 | serializer: { 46 | createModuleIdFactory: createModuleIdFactory, // 给 bundle 一个id 避免冲突 cli 源码中这个id 是从1 开始 自增的 47 | processModuleFilter: postProcessModulesFilter, // 返回false 就不会build 进去 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNM", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "react-native start --port=8082 ", 8 | "build:common": "react-native bundle --platform android --dev false --entry-file ./common.js --bundle-output ./android/app/src/main/assets/common.android.bundle --assets-dest ./android/app/src/main/res --config ./metro.common.config.js --minify true --reset-cache", 9 | "build:index": "react-native bundle --platform android --dev false --entry-file ./index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res --config ./metro.main.config.js --minify true --reset-cache", 10 | "build:bu1": "react-native bundle --platform android --dev false --entry-file ./Bu1.js --bundle-output ./android/app/src/main/assets/bu1.android.bundle --assets-dest ./android/app/src/main/res --config ./metro.main.config.js --minify true --reset-cache", 11 | "build:bu2": "react-native bundle --platform android --dev false --entry-file ./Bu2.js --bundle-output ./android/app/src/main/assets/bu2.android.bundle --assets-dest ./android/app/src/main/res --config ./metro.main.config.js --minify true --reset-cache", 12 | 13 | "build:common-ios": "react-native bundle --platform ios --dev false --entry-file ./common.js --bundle-output ./bundle/common.ios.bundle --config ./metro.common.config.js --minify false --reset-cache", 14 | "build:ios1": "react-native bundle --entry-file ./IOS.js --bundle-output ./bundle/IOS.ios.bundle --platform ios --assets-dest ./bundle --config ./metro.main.config.js --minify false --dev false", 15 | "build:ios2": "react-native bundle --entry-file ./IOS2.js --bundle-output ./bundle/IOS2.ios.bundle --platform ios --assets-dest ./bundle --config ./metro.main.config.js --minify false --dev false" 16 | }, 17 | "dependencies": { 18 | "@react-native-community/async-storage": "^1.12.1", 19 | "body-parser": "^1.20.0", 20 | "compressing": "^1.6.2", 21 | "express": "^4.18.1", 22 | "multer": "^1.4.5-lts.1", 23 | "react": "18.1.0", 24 | "react-native": "^0.70.1", 25 | "react-native-device-info": "^10.2.0", 26 | "react-native-storage": "^1.0.1", 27 | "sqlite3": "^5.1.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/assets/imgs/bigImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/assets/imgs/bigImage.png -------------------------------------------------------------------------------- /src/assets/imgs/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/assets/imgs/default.png -------------------------------------------------------------------------------- /src/assets/imgs/default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/assets/imgs/default@2x.png -------------------------------------------------------------------------------- /src/assets/imgs/default@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/assets/imgs/default@3x.png -------------------------------------------------------------------------------- /src/assets/imgs/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/assets/imgs/test.png -------------------------------------------------------------------------------- /src/modules/Business1/assets/img/1024_500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/modules/Business1/assets/img/1024_500.png -------------------------------------------------------------------------------- /src/modules/Business1/assets/img/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BM-laoli/Android-IOS-ReactNative/44ebe562730ed5187d42d917ef11b14bfcc13d26/src/modules/Business1/assets/img/test.png -------------------------------------------------------------------------------- /src/modules/Business1/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | Image, 7 | ScrollView, 8 | Button, 9 | } from "react-native"; 10 | import Imgx from "./assets/img/1024_500.png"; 11 | import { navigation } from "../../../common/utils"; 12 | // 整个App 的骨架,基础包 更新要严格控制 13 | const Frame = (props) => { 14 | useEffect(() => { 15 | init(); 16 | console.log("初始化"); 17 | return () => { 18 | console.log("销毁"); 19 | }; 20 | }, []); 21 | 22 | const init = async () => { 23 | const params = await navigation.getFromActivity(); 24 | console.log("params", params); 25 | }; 26 | 27 | return ( 28 | 29 | BU1 30 |