├── FirstProject ├── .buckconfig ├── .flowconfig ├── .gitignore ├── .watchmanconfig ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── index.android.bundle │ │ │ ├── java │ │ │ └── com │ │ │ │ └── firstproject │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainApplication.java │ │ │ │ ├── app │ │ │ │ └── AppReactPackage.java │ │ │ │ ├── module │ │ │ │ ├── ReactPtrLayout.java │ │ │ │ └── ReactRoundedImageView.java │ │ │ │ ├── ptr │ │ │ │ ├── DragonEggAminView.java │ │ │ │ ├── PluPtrHeaderView.java │ │ │ │ ├── PtrFrameLayout.java │ │ │ │ ├── PtrHeaderHandler.java │ │ │ │ ├── PtrState.java │ │ │ │ └── RefreshEvent.java │ │ │ │ └── utils │ │ │ │ ├── ImageHelper.java │ │ │ │ └── UIHelper.java │ │ │ └── res │ │ │ ├── drawable-xhdpi │ │ │ ├── egg0.png │ │ │ ├── egg1.png │ │ │ ├── egg2.png │ │ │ ├── egg3.png │ │ │ ├── egg4.png │ │ │ ├── egg5.png │ │ │ ├── ic_arrow_go.png │ │ │ ├── ic_column_h.png │ │ │ ├── ic_top_avatar_focus.png │ │ │ ├── icon_viewer.png │ │ │ ├── img_grey1.png │ │ │ ├── pic_cutline.png │ │ │ ├── tab_back.png │ │ │ ├── tab_ent_h.png │ │ │ ├── tab_ent_n.png │ │ │ ├── tab_game_h.png │ │ │ ├── tab_game_n.png │ │ │ ├── tab_home_h.png │ │ │ ├── tab_home_n.png │ │ │ ├── tab_search.png │ │ │ ├── tab_suipai_h.png │ │ │ └── tab_suipai_n.png │ │ │ ├── layout │ │ │ ├── dragon_layout.xml │ │ │ ├── head_text_layout.xml │ │ │ ├── layout_select_round.xml │ │ │ └── ptr_layout.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── no_pic_horizontal.png │ │ │ └── no_pic_horizontal_col.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── keystores │ │ ├── BUCK │ │ └── debug.keystore.properties │ └── settings.gradle ├── appComponent │ ├── CommonComponent.js │ ├── Constants.js │ ├── EntPage.js │ ├── HomePage.js │ ├── PtrFrameLayout.js │ ├── RoundedImageView.js │ ├── Routes.js │ ├── TabBar.js │ └── Toolbar.js ├── img │ └── ic_launcher.png ├── index.android.bundle.meta ├── index.android.js ├── index.ios.js ├── ios │ ├── FirstProject.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── FirstProject.xcscheme │ ├── FirstProject │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── FirstProjectTests │ │ ├── FirstProjectTests.m │ │ └── Info.plist └── package.json ├── README.md └── testUpdateRn └── BundleUpdateProject ├── .buckconfig ├── .flowconfig ├── .gitignore ├── .watchmanconfig ├── HotUpdate ├── drawable-hdpi │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png ├── drawable-mdpi │ ├── img_icon.png │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png ├── drawable-xhdpi │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png ├── drawable-xxhdpi │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png ├── drawable-xxxhdpi │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png ├── index.android.bundle └── index.android.bundle.meta ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── HotUpdate │ │ │ ├── drawable-hdpi │ │ │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png │ │ │ ├── drawable-mdpi │ │ │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png │ │ │ ├── drawable-xhdpi │ │ │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png │ │ │ ├── drawable-xxhdpi │ │ │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png │ │ │ ├── drawable-xxxhdpi │ │ │ └── node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png │ │ │ ├── index.android.bundle │ │ │ └── index.android.bundle.meta │ │ ├── java │ │ └── com │ │ │ └── bundleupdateproject │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ └── WelcomeActivity.java │ │ └── res │ │ ├── layout │ │ └── activity_welcome.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── bg_welcome.png │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystores │ ├── BUCK │ └── debug.keystore.properties ├── settings.gradle └── update │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── update │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── update │ │ │ ├── BundleUpdateCallBack.java │ │ │ ├── FileUtils.java │ │ │ ├── UpdateConstants.java │ │ │ ├── UpdateManager.java │ │ │ ├── UpdatePush.java │ │ │ └── UpdateUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── update │ └── ExampleUnitTest.java ├── img └── icon.png ├── index.android.js ├── index.ios.js ├── ios ├── BundleUpdateProject.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── BundleUpdateProject.xcscheme ├── BundleUpdateProject │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── BundleUpdateProjectTests │ ├── BundleUpdateProjectTests.m │ └── Info.plist └── package.json /FirstProject/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /FirstProject/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.android.js 5 | 6 | # Ignore templates with `@flow` in header 7 | .*/local-cli/generator.* 8 | 9 | # Ignore malformed json 10 | .*/node_modules/y18n/test/.*\.json 11 | 12 | [include] 13 | 14 | [libs] 15 | node_modules/react-native/Libraries/react-native/react-native-interface.js 16 | node_modules/react-native/flow 17 | flow/ 18 | 19 | [options] 20 | module.system=haste 21 | 22 | esproposal.class_static_fields=enable 23 | esproposal.class_instance_fields=enable 24 | 25 | experimental.strict_type_args=true 26 | 27 | munge_underscores=true 28 | 29 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 30 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 31 | 32 | suppress_type=$FlowIssue 33 | suppress_type=$FlowFixMe 34 | suppress_type=$FixMe 35 | 36 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 39 | 40 | [version] 41 | ^0.27.0 42 | -------------------------------------------------------------------------------- /FirstProject/.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 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | *.iml 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | android/app/libs 41 | android/keystores/debug.keystore 42 | -------------------------------------------------------------------------------- /FirstProject/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /FirstProject/android/app/BUCK: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # To learn about Buck see [Docs](https://buckbuild.com/). 4 | # To run your application with Buck: 5 | # - install Buck 6 | # - `npm start` - to start the packager 7 | # - `cd android` 8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US` 9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 10 | # - `buck install -r android/app` - compile, install and run application 11 | # 12 | 13 | lib_deps = [] 14 | for jarfile in glob(['libs/*.jar']): 15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) 16 | lib_deps.append(':' + name) 17 | prebuilt_jar( 18 | name = name, 19 | binary_jar = jarfile, 20 | ) 21 | 22 | for aarfile in glob(['libs/*.aar']): 23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) 24 | lib_deps.append(':' + name) 25 | android_prebuilt_aar( 26 | name = name, 27 | aar = aarfile, 28 | ) 29 | 30 | android_library( 31 | name = 'all-libs', 32 | exported_deps = lib_deps 33 | ) 34 | 35 | android_library( 36 | name = 'app-code', 37 | srcs = glob([ 38 | 'src/main/java/**/*.java', 39 | ]), 40 | deps = [ 41 | ':all-libs', 42 | ':build_config', 43 | ':res', 44 | ], 45 | ) 46 | 47 | android_build_config( 48 | name = 'build_config', 49 | package = 'com.firstproject', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.firstproject', 56 | ) 57 | 58 | android_binary( 59 | name = 'app', 60 | package_type = 'debug', 61 | manifest = 'src/main/AndroidManifest.xml', 62 | keystore = '//android/keystores:debug', 63 | deps = [ 64 | ':app-code', 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /FirstProject/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"] 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = false 84 | 85 | android { 86 | compileSdkVersion 23 87 | buildToolsVersion "23.0.1" 88 | 89 | defaultConfig { 90 | applicationId "com.firstproject" 91 | minSdkVersion 16 92 | targetSdkVersion 22 93 | versionCode 1 94 | versionName "1.0" 95 | ndk { 96 | abiFilters "armeabi-v7a", "x86" 97 | } 98 | } 99 | splits { 100 | abi { 101 | reset() 102 | enable enableSeparateBuildPerCPUArchitecture 103 | universalApk false // If true, also generate a universal APK 104 | include "armeabi-v7a", "x86" 105 | } 106 | } 107 | buildTypes { 108 | release { 109 | minifyEnabled enableProguardInReleaseBuilds 110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 111 | } 112 | } 113 | // applicationVariants are e.g. debug, release 114 | applicationVariants.all { variant -> 115 | variant.outputs.each { output -> 116 | // For each separate APK per architecture, set a unique version code as described here: 117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 118 | def versionCodes = ["armeabi-v7a":1, "x86":2] 119 | def abi = output.getFilter(OutputFile.ABI) 120 | if (abi != null) { // null for the universal-debug, universal-release variants 121 | output.versionCodeOverride = 122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 123 | } 124 | } 125 | } 126 | } 127 | 128 | dependencies { 129 | compile project(':react-native-code-push') 130 | compile fileTree(include: ['*.jar'], dir: 'libs') 131 | compile 'com.android.support:appcompat-v7:23.0.1' 132 | compile 'com.facebook.react:react-native:+' 133 | // From node_modules 134 | compile 'com.joooonho:selectableroundedimageview:1.0.1' 135 | compile files('libs/universal-image-loader-1.9.5.jar') 136 | } 137 | 138 | // Run this once to be able to run the application with BUCK 139 | // puts all compile dependencies into folder libs for BUCK to use 140 | task copyDownloadableDepsToLibs(type: Copy) { 141 | from configurations.compile 142 | into 'libs' 143 | } 144 | -------------------------------------------------------------------------------- /FirstProject/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # okhttp 54 | 55 | -keepattributes Signature 56 | -keepattributes *Annotation* 57 | -keep class okhttp3.** { *; } 58 | -keep interface okhttp3.** { *; } 59 | -dontwarn okhttp3.** 60 | 61 | # okio 62 | 63 | -keep class sun.misc.Unsafe { *; } 64 | -dontwarn java.nio.file.* 65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 66 | -dontwarn okio.** 67 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.firstproject; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.microsoft.codepush.react.CodePush; 5 | 6 | public class MainActivity extends ReactActivity { 7 | 8 | /** 9 | * Returns the name of the main component registered from JavaScript. 10 | * This is used to schedule rendering of the component. 11 | */ 12 | @Override 13 | protected String getMainComponentName() { 14 | return "FirstProject"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.firstproject; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.firstproject.app.AppReactPackage; 11 | import com.firstproject.utils.ImageHelper; 12 | import com.microsoft.codepush.react.CodePush; 13 | import com.nostra13.universalimageloader.core.ImageLoader; 14 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 15 | 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | public class MainApplication extends Application implements ReactApplication { 22 | 23 | 24 | private static MainApplication mApp; 25 | private static Context appContext; 26 | 27 | public static MainApplication getInstance() { 28 | return mApp; 29 | } 30 | 31 | public static Context getAppContext() { 32 | return appContext; 33 | } 34 | 35 | /** 36 | * Name │ Deployment Key │ 37 | ├────────────┼───────────────────────────────────────┤ 38 | │ Production │ m-riu3kK1__kGboK4WPIwBYs7ZwzEygDCEa5e │ 39 | ├────────────┼───────────────────────────────────────┤ 40 | │ Staging │ zi1vEIim9-i5bkMl9fQ32EA_4LBxEygDCEa5e │ 41 | */ 42 | 43 | 44 | @Override 45 | public void onCreate() { 46 | super.onCreate(); 47 | if (mApp == null) { 48 | mApp = this; 49 | appContext = getApplicationContext(); 50 | initImgLoader(); 51 | 52 | } 53 | } 54 | 55 | public void initImgLoader() { 56 | ImageLoaderConfiguration imageLoaderConfig = ImageHelper.initImageConfigBuilder().build(); 57 | ImageLoader.getInstance().init(imageLoaderConfig); 58 | } 59 | 60 | public static ImageLoader initImageLoader() { 61 | ImageLoader imageLoader = ImageLoader.getInstance(); 62 | // imageLoader.resume(); // v3.0前防止图片加载线程被pause后所有图片都加载不了;v3.5每次都getInstance()不需要resume 63 | return imageLoader; 64 | } 65 | 66 | 67 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 68 | @Override 69 | protected boolean getUseDeveloperSupport() { 70 | return false; 71 | } 72 | 73 | @Override 74 | protected List getPackages() { 75 | return Arrays.asList( 76 | new MainReactPackage(), 77 | new AppReactPackage(), 78 | new CodePush("m-riu3kK1__kGboK4WPIwBYs7ZwzEygDCEa5e", MainApplication.this, false) 79 | ); 80 | } 81 | 82 | @Nullable 83 | @Override 84 | protected String getJSBundleFile() { 85 | return CodePush.getJSBundleFile(); 86 | } 87 | }; 88 | 89 | @Override 90 | public ReactNativeHost getReactNativeHost() { 91 | return mReactNativeHost; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/app/AppReactPackage.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.app; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | import com.firstproject.module.ReactPtrLayout; 9 | import com.firstproject.module.ReactRoundedImageView; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by lijie on 16/7/13. 17 | */ 18 | public class AppReactPackage implements ReactPackage { 19 | @Override 20 | public List createNativeModules(ReactApplicationContext reactContext) { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List> createJSModules() { 26 | return Collections.emptyList(); 27 | } 28 | 29 | @Override 30 | public List createViewManagers(ReactApplicationContext reactContext) { 31 | List result = new ArrayList(); 32 | result.add(new ReactRoundedImageView()); 33 | result.add(new ReactPtrLayout()); 34 | return result; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/module/ReactPtrLayout.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.module; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | 6 | import com.facebook.react.bridge.ReadableArray; 7 | import com.facebook.react.common.MapBuilder; 8 | import com.facebook.react.common.SystemClock; 9 | import com.facebook.react.uimanager.ThemedReactContext; 10 | import com.facebook.react.uimanager.UIManagerModule; 11 | import com.facebook.react.uimanager.ViewGroupManager; 12 | import com.firstproject.R; 13 | import com.firstproject.ptr.PtrFrameLayout; 14 | import com.firstproject.ptr.PtrState; 15 | import com.firstproject.ptr.RefreshEvent; 16 | 17 | import java.util.Map; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * Created by lijie on 16/7/13. 23 | */ 24 | public class ReactPtrLayout extends ViewGroupManager { 25 | 26 | private static final int STOP_REFRESH=1; 27 | 28 | @Override 29 | public String getName() { 30 | return "PtrFrameLayout"; 31 | } 32 | 33 | @Override 34 | protected PtrFrameLayout createViewInstance(ThemedReactContext reactContext) { 35 | final PtrFrameLayout rootView= (PtrFrameLayout)LayoutInflater.from(reactContext).inflate(R.layout.ptr_layout,null); 36 | return rootView; 37 | } 38 | 39 | @Nullable 40 | @Override 41 | public Map getCommandsMap() { 42 | return MapBuilder.of("stop_refresh",STOP_REFRESH); 43 | } 44 | 45 | @Override 46 | public void receiveCommand(PtrFrameLayout root, int commandId, @Nullable ReadableArray args) { 47 | switch (commandId){ 48 | case STOP_REFRESH: 49 | root.completeRefresh(PtrState.REFRESH_SUCCESS); 50 | return; 51 | } 52 | } 53 | 54 | @Override 55 | protected void addEventEmitters(final ThemedReactContext reactContext, final PtrFrameLayout view) { 56 | super.addEventEmitters(reactContext, view); 57 | view.setOnRefreshListener(new PtrFrameLayout.OnRefreshListener() { 58 | @Override 59 | public void onRefresh() { 60 | reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher() 61 | .dispatchEvent(new RefreshEvent(view.getId(), SystemClock.nanoTime())); 62 | } 63 | }); 64 | } 65 | 66 | @Override 67 | public Map getExportedCustomDirectEventTypeConstants() { 68 | return MapBuilder.builder() 69 | .put("topRefresh", MapBuilder.of("registrationName", "onRefresh")) 70 | .build(); 71 | } 72 | 73 | 74 | @Override 75 | public void addView(PtrFrameLayout parent, View child, int index) { 76 | super.addView(parent, child, index); 77 | parent.updateLayout(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/module/ReactRoundedImageView.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.module; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | 6 | import com.facebook.react.uimanager.SimpleViewManager; 7 | import com.facebook.react.uimanager.ThemedReactContext; 8 | import com.facebook.react.uimanager.annotations.ReactProp; 9 | import com.firstproject.MainApplication; 10 | import com.firstproject.R; 11 | import com.joooonho.SelectableRoundedImageView; 12 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 13 | import com.nostra13.universalimageloader.core.ImageLoader; 14 | import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; 15 | 16 | /** 17 | * Created by lijie on 16/7/13. 18 | */ 19 | public class ReactRoundedImageView extends SimpleViewManager { 20 | 21 | private static final String MODULE_NAME="AndroidRoundImage"; 22 | 23 | private ImageLoader mImageLoader; 24 | private DisplayImageOptions options; 25 | 26 | @Override 27 | public String getName() { 28 | return MODULE_NAME; 29 | } 30 | 31 | @Override 32 | protected SelectableRoundedImageView createViewInstance(ThemedReactContext reactContext) { 33 | mImageLoader = MainApplication.initImageLoader(); 34 | // options = ImageHelper.initImageBuilder(R.drawable.no_pic_horizontal_col, true, ImageScaleType.EXACTLY ).build(); 35 | options = new DisplayImageOptions.Builder() 36 | .showImageOnLoading(R.mipmap.no_pic_horizontal_col) 37 | .showImageForEmptyUri(R.mipmap.no_pic_horizontal_col) 38 | .showImageOnFail(R.mipmap.no_pic_horizontal_col) 39 | .cacheInMemory(true) 40 | .cacheOnDisk(true) 41 | .considerExifParams(true) 42 | .displayer(new SimpleBitmapDisplayer()) 43 | .build(); 44 | View rootView= LayoutInflater.from(reactContext).inflate(R.layout.layout_select_round,null); 45 | return (SelectableRoundedImageView) rootView; 46 | } 47 | 48 | @ReactProp(name = "url") 49 | public void setUrl(SelectableRoundedImageView simpleDraweeView, String url){ 50 | mImageLoader.displayImage(url,simpleDraweeView, options); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/ptr/DragonEggAminView.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.ptr; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.util.AttributeSet; 10 | import android.util.Log; 11 | import android.view.View; 12 | 13 | import com.firstproject.R; 14 | 15 | /** 16 | * Created by liuj on 2016/5/4. 17 | * 龙蛋刷新动画 18 | */ 19 | public class DragonEggAminView extends View { 20 | 21 | private static final String TAG = "DragEggAnim"; 22 | 23 | public static enum State { 24 | Init, 25 | Moving, 26 | AnimStart 27 | } 28 | 29 | private State currentState; 30 | private int currentOffset; 31 | 32 | private Paint paint; 33 | private Bitmap topShell; 34 | private Bitmap fullEgg; 35 | private Bitmap dragonEgg; 36 | private Bitmap[] animArr; 37 | 38 | private int currentAnimIndex; 39 | 40 | public DragonEggAminView(Context context) { 41 | this(context, null); 42 | } 43 | 44 | public DragonEggAminView(Context context, AttributeSet attrs) { 45 | this(context, attrs, 0); 46 | } 47 | 48 | public DragonEggAminView(Context context, AttributeSet attrs, int defStyleAttr) { 49 | super(context, attrs, defStyleAttr); 50 | init(context); 51 | } 52 | private static Bitmap small(Bitmap bitmap) { 53 | Matrix matrix = new Matrix(); 54 | matrix.postScale(0.7f,0.7f); //长和宽放大缩小的比例 55 | Bitmap resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true); 56 | return resizeBmp; 57 | } 58 | 59 | private void init(Context context) { 60 | paint = new Paint(); 61 | topShell =small(BitmapFactory.decodeResource(getResources(), R.drawable.egg2)); 62 | fullEgg = small(BitmapFactory.decodeResource(getResources(), R.drawable.egg0)); 63 | dragonEgg = small(BitmapFactory.decodeResource(getResources(), R.drawable.egg3)); 64 | animArr = new Bitmap[3]; 65 | animArr[0] = dragonEgg; 66 | animArr[1] = small(BitmapFactory.decodeResource(getResources(), R.drawable.egg4)); 67 | animArr[2] = small(BitmapFactory.decodeResource(getResources(), R.drawable.egg5)); 68 | currentState = State.Init; 69 | } 70 | 71 | 72 | public void updateState(State state) { 73 | if (currentState != state) { 74 | currentState = state; 75 | currentAnimIndex = 0; 76 | invalidate(); 77 | } 78 | } 79 | 80 | public void updateMovePos(int offset, PtrState state) { 81 | if (offset >0) { 82 | currentState = State.Moving; 83 | currentOffset = (int) (offset*1.5f); 84 | } else { 85 | currentOffset = 0; 86 | currentState = State.Init; 87 | } 88 | if (state == PtrState.REFRESHING) { 89 | currentState = State.AnimStart; 90 | } else { 91 | currentAnimIndex = 0; 92 | invalidate(); 93 | } 94 | 95 | } 96 | 97 | 98 | public int getMaxOpenHeight() { 99 | return (int) ((getHeight() / 2 + topShell.getHeight() / 2)/1.5f); 100 | } 101 | 102 | @Override 103 | protected void onDraw(Canvas canvas) { 104 | super.onDraw(canvas); 105 | switch (currentState) { 106 | case Init: 107 | canvas.drawBitmap(fullEgg, getWidth() / 2 - fullEgg.getWidth() / 2, getHeight() / 2 - fullEgg.getHeight() / 2, paint); 108 | break; 109 | case Moving: 110 | canvas.drawBitmap(dragonEgg, getWidth() / 2 - dragonEgg.getWidth() / 2, getHeight() / 2 - dragonEgg.getHeight() / 2, paint); 111 | Log.d(TAG, "currentOffset"+currentOffset + ""); 112 | canvas.drawBitmap(topShell, getWidth() / 2 - topShell.getWidth() / 2, getHeight() / 2 - topShell.getHeight() / 2 - currentOffset, paint); 113 | break; 114 | case AnimStart: 115 | Bitmap animFrame = animArr[currentAnimIndex]; 116 | canvas.drawBitmap(animFrame, getWidth() / 2 - animFrame.getWidth() / 2, getHeight() / 2 - animFrame.getHeight() / 2, paint); 117 | currentAnimIndex = (currentAnimIndex + 1) % animArr.length; 118 | postInvalidateDelayed(150); 119 | break; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/ptr/PluPtrHeaderView.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.ptr; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.util.TypedValue; 9 | import android.view.Gravity; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.firstproject.R; 16 | 17 | import java.text.DateFormat; 18 | import java.text.SimpleDateFormat; 19 | import java.util.Calendar; 20 | import java.util.Date; 21 | 22 | /** 23 | * Created by lijie on 16/7/13. 24 | */ 25 | public class PluPtrHeaderView extends LinearLayout implements PtrHeaderHandler { 26 | 27 | private static final String UPDATE_TIME_KEY = "update_time"; 28 | private static final int DP_ANM_SIZE = 60; 29 | 30 | private DateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm"); 31 | private DateFormat timeFormat = new SimpleDateFormat("HH:mm"); 32 | 33 | private SharedPreferences sharedPreferences; 34 | private DragonEggAminView dragonEggAminView; 35 | private TextView refreshStateTv; 36 | private TextView updateTimeTv; 37 | private String key; 38 | 39 | private int currentOffset; 40 | 41 | 42 | public PluPtrHeaderView(Context context) { 43 | super(context); 44 | init(context); 45 | } 46 | 47 | public PluPtrHeaderView(Context context, AttributeSet attrs) { 48 | super(context, attrs); 49 | init(context); 50 | } 51 | 52 | public PluPtrHeaderView(Context context, AttributeSet attrs, int defStyleAttr) { 53 | super(context, attrs, defStyleAttr); 54 | init(context); 55 | } 56 | 57 | private void init(Context context) { 58 | 59 | setOrientation(HORIZONTAL); 60 | setGravity(Gravity.CENTER); 61 | 62 | dragonEggAminView = new DragonEggAminView(getContext()); 63 | int animViewSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DP_ANM_SIZE, getResources().getDisplayMetrics()); 64 | dragonEggAminView.setLayoutParams(new MarginLayoutParams(animViewSize, animViewSize)); 65 | addView(dragonEggAminView); 66 | 67 | View textLayout = LayoutInflater.from(context).inflate(R.layout.head_text_layout, null); 68 | refreshStateTv = (TextView) textLayout.findViewById(R.id.tv_state); 69 | updateTimeTv = (TextView) textLayout.findViewById(R.id.tv_time); 70 | addView(textLayout); 71 | 72 | setVisibility(View.INVISIBLE); 73 | 74 | } 75 | 76 | 77 | @Override 78 | protected void onAttachedToWindow() { 79 | super.onAttachedToWindow(); 80 | String lastUpdateTime = getFormatUpdateTime(getLastUpdateTime()); 81 | updateTimeTv(lastUpdateTime); 82 | } 83 | 84 | @Override 85 | public void onPositionUpdate(int offset, PtrState state) { 86 | 87 | currentOffset = offset; 88 | 89 | //正在刷新不改变龙蛋动画 90 | if (state == PtrState.REFRESHING) { 91 | return; 92 | } 93 | 94 | if (offset > 0) { 95 | dragonEggAminView.updateMovePos(offset - getHeight() * 2 / 3, state); 96 | if (getVisibility() != View.VISIBLE) 97 | setVisibility(View.VISIBLE); 98 | } else { 99 | dragonEggAminView.updateMovePos(0, state); 100 | if (getVisibility() != View.INVISIBLE) { 101 | setVisibility(View.INVISIBLE); 102 | } 103 | } 104 | Log.d("ptr", offset + "," + getHeight()); 105 | if (state == PtrState.INIT) { 106 | if (offset < getRefreshHeight()) { 107 | refreshStateTv.setText(R.string.ptr_pull_to_refresh); 108 | } else { 109 | refreshStateTv.setText(R.string.ptr_release_to_refresh); 110 | } 111 | } 112 | 113 | } 114 | 115 | @Override 116 | public void onRefreshing() { 117 | Log.d("headerView", "onrefreshing"); 118 | if (getVisibility() != View.VISIBLE) { 119 | setVisibility(View.VISIBLE); 120 | } 121 | dragonEggAminView.updateState(DragonEggAminView.State.AnimStart); 122 | refreshStateTv.setText(R.string.ptr_refreshing); 123 | } 124 | 125 | @Override 126 | public void onCompleteRefreshing(PtrState state) { 127 | if (currentOffset <= 0) { 128 | if (getVisibility() != View.INVISIBLE) { 129 | setVisibility(View.INVISIBLE); 130 | } 131 | } 132 | if (state == PtrState.REFRESH_SUCCESS) { 133 | refreshStateTv.setText(R.string.ptr_refresh_complete); 134 | handleUpdateSuccess(); 135 | } else { 136 | refreshStateTv.setText(R.string.ptr_refresh_failure); 137 | } 138 | dragonEggAminView.updateMovePos(dragonEggAminView.getMaxOpenHeight(), PtrState.INIT); 139 | } 140 | 141 | @Override 142 | public int getRefreshHeight() { 143 | return getHeight() * 2 / 3 + dragonEggAminView.getMaxOpenHeight(); 144 | } 145 | 146 | 147 | /** 148 | * 更新刷新时间 149 | */ 150 | public void updateRefreshTime() { 151 | handleUpdateSuccess(); 152 | } 153 | 154 | private SharedPreferences getSharedPreference() { 155 | if (sharedPreferences == null && !TextUtils.isEmpty(key)) { 156 | sharedPreferences = getContext().getSharedPreferences(key, 0); 157 | } 158 | return sharedPreferences; 159 | } 160 | 161 | 162 | /** 163 | * 设置保存更新时间唯一键值 164 | * 165 | * @param key 166 | */ 167 | public void setSaveUpdateTimeKey(String key) { 168 | this.key = key; 169 | sharedPreferences = getSharedPreference(); 170 | } 171 | 172 | /** 173 | * 保存更新时间 174 | */ 175 | private void saveUpdateTime() { 176 | long time = System.currentTimeMillis(); 177 | SharedPreferences sharedPreferences = getSharedPreference(); 178 | if (sharedPreferences != null) { 179 | sharedPreferences.edit().putLong(UPDATE_TIME_KEY, time).apply(); 180 | } 181 | } 182 | 183 | /** 184 | * 获取上一次更新时间 185 | * 186 | * @return 187 | */ 188 | private long getLastUpdateTime() { 189 | SharedPreferences sharedPreferences = getSharedPreference(); 190 | if (sharedPreferences != null) { 191 | return sharedPreferences.getLong(UPDATE_TIME_KEY, 0); 192 | } 193 | return 0; 194 | } 195 | 196 | /** 197 | * 获取格式化更新时间文本 198 | * 199 | * @param time 200 | * @return 201 | */ 202 | private String getFormatUpdateTime(long time) { 203 | if (time == 0) { 204 | return ""; 205 | } 206 | long sysDate = Calendar.getInstance().getTimeInMillis() / (1000 * 3600 * 24); 207 | long updateDate = time / (1000 * 3600 * 24); 208 | if (sysDate == updateDate) { 209 | return String.format(getResources().getString(R.string.ptr_today_time), timeFormat.format(new Date(time))); 210 | } 211 | 212 | return dateFormat.format(new Date(time)); 213 | } 214 | 215 | private void handleUpdateSuccess() { 216 | String updateTime = getFormatUpdateTime(System.currentTimeMillis()); 217 | updateTimeTv(updateTime); 218 | saveUpdateTime(); 219 | } 220 | 221 | private void updateTimeTv(String formatTime) { 222 | if (!TextUtils.isEmpty(formatTime)) { 223 | String txt = getResources().getString(R.string.ptr_update_time) + " " + formatTime; 224 | updateTimeTv.setText(txt); 225 | } else { 226 | updateTimeTv.setText(getResources().getString(R.string.ptr_update_time)); 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/ptr/PtrHeaderHandler.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.ptr; 2 | 3 | /** 4 | * Created by lijie on 16/7/13. 5 | */ 6 | public interface PtrHeaderHandler { 7 | 8 | /** 9 | * 当下拉位置发生改变 10 | * 11 | * @param offset 偏移 12 | * @param state 状态 13 | */ 14 | void onPositionUpdate(int offset, PtrState state); 15 | 16 | void onRefreshing(); 17 | 18 | /** 19 | * 完成刷新 20 | * 21 | * @param state 刷新状态 22 | */ 23 | void onCompleteRefreshing(PtrState state); 24 | 25 | 26 | /** 27 | * 获取刷新的下拉高度 28 | * 29 | * @return 30 | */ 31 | int getRefreshHeight(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/ptr/PtrState.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.ptr; 2 | 3 | /** 4 | * Created by lijie on 16/7/13. 5 | */ 6 | public enum PtrState { 7 | INIT, 8 | REFRESHING, 9 | REFRESH_SUCCESS, 10 | REFRESH_FAILURE 11 | } -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/ptr/RefreshEvent.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.ptr; 2 | 3 | import com.facebook.react.uimanager.events.Event; 4 | import com.facebook.react.uimanager.events.RCTEventEmitter; 5 | 6 | /** 7 | * Created by lijie on 16/7/13. 8 | */ 9 | public class RefreshEvent extends Event { 10 | 11 | public RefreshEvent(int viewTag, long timestampMs) { 12 | super(viewTag, timestampMs); 13 | } 14 | 15 | @Override 16 | public String getEventName() { 17 | return "topRefresh"; 18 | } 19 | 20 | @Override 21 | public void dispatch(RCTEventEmitter rctEventEmitter) { 22 | rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/utils/ImageHelper.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.utils; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.firstproject.MainApplication; 6 | import com.firstproject.R; 7 | import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache; 8 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 9 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 10 | import com.nostra13.universalimageloader.core.assist.ImageScaleType; 11 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 12 | import com.nostra13.universalimageloader.utils.StorageUtils; 13 | 14 | import java.io.File; 15 | 16 | /** 17 | * Created by plu on 2015/12/15. 18 | *

19 | * 初始化图片加载类 20 | *

21 | * 主要参数:默认加载图,是否缓存本地,imageScaleType 22 | *

23 | * https://github.com/nostra13/Android-Universal-Image-Loader 24 | */ 25 | public class ImageHelper { 26 | 27 | public static DisplayImageOptions.Builder initImageBuilder() { 28 | return initImageBuilder(R.mipmap.no_pic_horizontal, true, null); 29 | } 30 | 31 | public static DisplayImageOptions.Builder initImageBuilder(boolean isDiskCache) { 32 | return initImageBuilder(R.mipmap.no_pic_horizontal, isDiskCache, null); 33 | } 34 | 35 | public static DisplayImageOptions.Builder initImageBuilder(int defDrawableId, boolean isDiskCache) { 36 | return initImageBuilder(defDrawableId, isDiskCache, null); 37 | } 38 | 39 | public static DisplayImageOptions.Builder initImageBuilder(int defDrawableId, boolean isDiskCache, ImageScaleType scaleType) { 40 | DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder() 41 | .bitmapConfig(Bitmap.Config.RGB_565) 42 | // 设置图片的解码类型 43 | .showImageOnLoading(defDrawableId) 44 | .showImageForEmptyUri(defDrawableId) // 设置图片Uri为空或是错误的时候显示的图片 45 | .showImageOnFail(defDrawableId) // 设置图片加载/解码过程中错误时候显示的图片 46 | .cacheInMemory(true) // 设置下载的图片是否缓存在内存中 47 | .cacheOnDisk(isDiskCache); // 设置下载的图片是否缓存在SD卡中 48 | 49 | if (scaleType != null && scaleType instanceof ImageScaleType) { 50 | builder.imageScaleType(scaleType); // 设置ImageView的显示属性 51 | } 52 | return builder; 53 | } 54 | 55 | public static DisplayImageOptions.Builder initImageBuilder(int defDrawableId, boolean inMemoryCache, boolean isDiskCache, ImageScaleType scaleType) { 56 | DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder() 57 | .bitmapConfig(Bitmap.Config.RGB_565) 58 | // 设置图片的解码类型 59 | .showImageOnLoading(defDrawableId) 60 | .showImageForEmptyUri(defDrawableId) // 设置图片Uri为空或是错误的时候显示的图片 61 | .showImageOnFail(defDrawableId) // 设置图片加载/解码过程中错误时候显示的图片 62 | .cacheInMemory(inMemoryCache) // 设置下载的图片是否缓存在内存中 63 | .cacheOnDisk(isDiskCache); // 设置下载的图片是否缓存在SD卡中 64 | 65 | if (scaleType != null && scaleType instanceof ImageScaleType) { 66 | builder.imageScaleType(scaleType); // 设置ImageView的显示属性 67 | } 68 | return builder; 69 | } 70 | 71 | 72 | 73 | public static ImageLoaderConfiguration.Builder initImageConfigBuilder() { 74 | File cacheDir = StorageUtils.getOwnCacheDirectory( 75 | MainApplication.getInstance().getApplicationContext(), "imageloader/Cache"); 76 | // PluLogUtil.log("-----cacheDir is " + cacheDir); 77 | ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(MainApplication.getInstance().getApplicationContext()) 78 | .denyCacheImageMultipleSizesInMemory() 79 | .memoryCacheSizePercentage(50) //availableMemoryPercent,设置内存缓存使用占应最大内存的比例 80 | .memoryCache(new LRULimitedMemoryCache(5 * 1024 * 1024)) // 弱引用自动管理内存,达到上限时先remove最不常用的 81 | // .diskCache(new LruDiskCache(cacheDir, new Md5FileNameGenerator(), 50 * 1024 * 1024)) 82 | // .memoryCacheExtraOptions(480, 800) // 设定内存图片缓存大小限制,不设置默认为屏幕的宽高 83 | // .memoryCacheSize(5 * 1024 * 1024) // 缓存到内存的最大数据 84 | // .memoryCache(new UsingFreqLimitedMemoryCache(10 * 1024 * 1024)) // 设定内存缓存为弱缓存 85 | /*.diskCacheFileCount(1000) // 缓存文件最大数量 86 | .diskCacheSize(50 * 1024 * 1024) // 缓存到文件的最大数据 87 | .diskCacheFileNameGenerator(new Md5FileNameGenerator()) 88 | .diskCache(new LimitedAgeDiskCache(cacheDir,10*60))//设置图片的磁盘缓存时间为10min,缓存时间超过10分钟就删除 */ // .diskCache(new UnlimitedDiskCache(cacheDir)) 89 | // .writeDebugLogs() // LOG打包时要去掉 90 | .threadPoolSize(3) 91 | .threadPriority(Thread.NORM_PRIORITY - 2) 92 | .tasksProcessingOrder(QueueProcessingType.LIFO); // 线程优先级:last in first out 93 | 94 | 95 | return builder; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/java/com/firstproject/utils/UIHelper.java: -------------------------------------------------------------------------------- 1 | package com.firstproject.utils; 2 | 3 | import android.support.v4.view.ViewCompat; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.widget.ListView; 7 | 8 | import com.facebook.react.views.view.ReactViewGroup; 9 | 10 | /** 11 | * Created by lijie on 16/7/13. 12 | */ 13 | public class UIHelper { 14 | private static final int SCROLL_UP = -1; 15 | 16 | private static final int SCROLL_DOWN = 1; 17 | /** 18 | * 是否可以下拉 19 | * 20 | * @param view 21 | * @return 22 | */ 23 | public static boolean canScrollDown(View view) { 24 | boolean isFirst = true; 25 | //对listView进行适配,判断是否滚至顶部 26 | if (view instanceof ListView) { 27 | isFirst = false; 28 | ListView listView = (ListView) view; 29 | if (listView.getChildCount() == 0) { 30 | isFirst = true; 31 | } else { 32 | View child = listView.getChildAt(0); 33 | if (listView.getFirstVisiblePosition() == 0) { 34 | isFirst = child.getTop() >= listView.getPaddingTop(); 35 | } 36 | } 37 | } 38 | else if(view instanceof ReactViewGroup){ 39 | isFirst=false; 40 | ReactViewGroup scrollView= (ReactViewGroup) view; 41 | if (scrollView.getChildCount()==0){ 42 | isFirst=true; 43 | } 44 | else{ 45 | View child=scrollView.getChildAt(0); 46 | isFirst=child.getTop()>=scrollView.getPaddingTop(); 47 | } 48 | Log.e("info","isScroll-------"+isFirst); 49 | } 50 | Log.e("info",!ViewCompat.canScrollVertically(view, SCROLL_UP)+"------"+isFirst+"-------"+view.getClass()); 51 | return !ViewCompat.canScrollVertically(view, SCROLL_UP) && isFirst; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg0.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg1.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg2.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg3.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg4.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/egg5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/egg5.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/ic_arrow_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/ic_arrow_go.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/ic_column_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/ic_column_h.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/ic_top_avatar_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/ic_top_avatar_focus.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/icon_viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/icon_viewer.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/img_grey1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/img_grey1.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/pic_cutline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/pic_cutline.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_back.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_ent_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_ent_h.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_ent_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_ent_n.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_game_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_game_h.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_game_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_game_n.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_home_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_home_h.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_home_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_home_n.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_search.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_suipai_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_suipai_h.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/drawable-xhdpi/tab_suipai_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/drawable-xhdpi/tab_suipai_n.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/layout/dragon_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/layout/head_text_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/layout/layout_select_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/layout/ptr_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-xhdpi/no_pic_horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-xhdpi/no_pic_horizontal.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-xhdpi/no_pic_horizontal_col.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-xhdpi/no_pic_horizontal_col.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FirstProject 4 | 5 | 下拉刷新 6 | 7 | 松开刷新 8 | 9 | 刷新中... 10 | 11 | 刷新完成 12 | 13 | 刷新失败 14 | 15 | 最后更新: 16 | 17 | 今天 %s 18 | 19 | -------------------------------------------------------------------------------- /FirstProject/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FirstProject/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FirstProject/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /FirstProject/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /FirstProject/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /FirstProject/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /FirstProject/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /FirstProject/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /FirstProject/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /FirstProject/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'FirstProject' 2 | 3 | include ':app' 4 | include ':react-native-code-push' 5 | project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app') 6 | -------------------------------------------------------------------------------- /FirstProject/appComponent/CommonComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | import React, { Component } from 'react'; 5 | import { 6 | View, 7 | ProgressBarAndroid, 8 | } from 'react-native'; 9 | 10 | class CommonComponents { 11 | static renderLoadingView() { 12 | return ( 13 | 14 | 15 | 16 | ) 17 | } 18 | } 19 | module.exports = CommonComponents; 20 | 21 | -------------------------------------------------------------------------------- /FirstProject/appComponent/Constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | let Constants={ 5 | TAB_ARRAYS:[ 6 | { 7 | name:'龙珠直播', 8 | normal:'tab_home_n', 9 | selected:'tab_home_h' 10 | }, 11 | { 12 | name:'游戏', 13 | normal:'tab_game_n', 14 | selected:'tab_game_h' 15 | }, 16 | { 17 | name:'随拍', 18 | normal:'tab_suipai_n', 19 | selected:'tab_suipai_h' 20 | }, 21 | { 22 | name:'娱乐', 23 | normal:'tab_ent_n', 24 | selected:'tab_ent_h' 25 | } 26 | ] 27 | }; 28 | 29 | module.exports=Constants; 30 | -------------------------------------------------------------------------------- /FirstProject/appComponent/EntPage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/14. 3 | */ 4 | 'use strict'; 5 | import React, { Component } from 'react'; 6 | import { 7 | StyleSheet, 8 | Text, 9 | View, 10 | TouchableNativeFeedback, 11 | TouchableOpacity, 12 | Alert, 13 | 14 | } from 'react-native'; 15 | 16 | export default class EntPage extends Component { 17 | render(){ 18 | return ( 19 | 20 | { 21 | }}> 22 | 23 | 更新 24 | 25 | 26 | 27 | ); 28 | } 29 | } -------------------------------------------------------------------------------- /FirstProject/appComponent/HomePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | StyleSheet, 8 | Text, 9 | View, 10 | Dimensions, 11 | ScrollView, 12 | Image, 13 | RefreshControl 14 | } from 'react-native'; 15 | 16 | import CommonComponent from './CommonComponent'; 17 | import Banner from 'react-native-banner'; 18 | import RoundImageView from './RoundedImageView'; 19 | const deviceWidth = Dimensions.get('window').width; 20 | const deviceHeight=Dimensions.get('window').height; 21 | import PtrFrameLayout from './PtrFrameLayout'; 22 | 23 | let bannerData=[]; 24 | let quickButton=[]; 25 | let columnData=[]; 26 | 27 | const DataState = { 28 | pending: 0, 29 | hasReached:1 30 | }; 31 | 32 | const KEY_SCROLL_VIEW="scroll_view"; 33 | 34 | var self; 35 | 36 | let hasRender=false; 37 | 38 | const KEY_REFRESH="key_refresh"; 39 | export default class HomePage extends Component { 40 | 41 | // 构造 42 | constructor(props) { 43 | super(props); 44 | // 初始状态 45 | this.state = { 46 | defaultIndex: 0, 47 | dataState:DataState.pending, 48 | isRefreshing:false, 49 | }; 50 | this.getRemoteData=this.getRemoteData.bind(this); 51 | this.parseData=this.parseData.bind(this); 52 | this.generateRootView=this.generateRootView.bind(this); 53 | this.newNumFormat=this.newNumFormat.bind(this); 54 | this.generateRoom=this.generateRoom.bind(this); 55 | this._onRefresh=this._onRefresh.bind(this); 56 | } 57 | 58 | 59 | newNumFormat(num){ 60 | let numDouble; 61 | if (num>10000){ 62 | numDouble=(num/10000).toFixed(1)+"万"; 63 | } 64 | else if(num>1000000){ 65 | numDouble=(num/1000000).toFixed(1)+"百万"; 66 | } 67 | else{ 68 | numDouble=num.valueOf(); 69 | } 70 | return numDouble; 71 | } 72 | 73 | 74 | parseData(responseObj){ 75 | if(responseObj){ 76 | //处理columns 77 | responseObj.data.columns.forEach((item,index,arrays)=>{ 78 | let channelsText=item.channelsText; 79 | let iconImg=item.game.icon; 80 | let name=item.game.name; 81 | let rooms=[]; 82 | item.rooms.forEach((child,pos,as)=>{ 83 | let previewImg=child.preview; 84 | let tag=child.channel.tag; 85 | let channelName=child.channel.name; 86 | let channelStatus=child.channel.status; 87 | let viewers=this.newNumFormat(child.viewers); 88 | rooms.push({ 89 | 'previewImg':previewImg, 90 | 'tag':tag, 91 | 'channelName':channelName, 92 | 'channelStatus':channelStatus, 93 | 'viewers':viewers 94 | }) 95 | }); 96 | columnData.push({ 97 | 'channelsText':channelsText, 98 | 'iconImg':iconImg, 99 | 'name':name, 100 | 'rooms':rooms 101 | }); 102 | }); 103 | //处理quickButton 104 | responseObj.data.quickbutton.forEach((item,index,arrays)=>{ 105 | quickButton.push(item.image); 106 | }); 107 | //处理banner 108 | responseObj.data.banner.forEach((item,index,arrays)=>{ 109 | let bannerImage=item.image; 110 | let bannerTitle=item.title; 111 | bannerData.push({ 112 | 'image':bannerImage, 113 | 'title':bannerTitle 114 | }); 115 | if(index===(arrays.length-1)){ 116 | this.setState({ 117 | dataState:DataState.hasReached 118 | }); 119 | this.refs[KEY_REFRESH].stopRefresh(); 120 | } 121 | }); 122 | } 123 | } 124 | 125 | clickListener(index) { 126 | 127 | } 128 | 129 | onMomentumScrollEnd(event, state) { 130 | this.defaultIndex = state.index; 131 | } 132 | 133 | 134 | getRemoteData(){ 135 | fetch('https://a4.plu.cn/api/home/personal?version=3.5&device=4',{ 136 | method:'get' 137 | }).then((response)=>{ 138 | if (response.ok){ 139 | response.json().then((data)=>{ 140 | this.parseData(data); 141 | }).catch((err)=>{ 142 | console.log("err----"+err); 143 | }); 144 | } 145 | }).catch((error)=>{ 146 | console.log("error---"+error); 147 | }); 148 | } 149 | 150 | componentWillMount() { 151 | self=this; 152 | this.getRemoteData(); 153 | } 154 | 155 | generateRoom(itemColumn){ 156 | let roomsLine=[]; 157 | for (let i=0;i 168 | 169 | {firstStream.tag} 170 | 171 | ; 172 | } 173 | else if(lastStream.tag){ 174 | tag2= 175 | 176 | {lastStream.tag} 177 | 178 | ; 179 | } 180 | } 181 | roomsLine.push( 182 | 183 | 184 | 189 | {tag1} 190 | 195 | {firstStream.channelName} 198 | 199 | 203 | 204 | {firstStream.viewers} 205 | 206 | 207 | 208 | 209 | {firstStream.channelStatus} 210 | 211 | 212 | 213 | 218 | {tag2} 219 | 224 | {lastStream.channelName} 227 | 228 | 232 | 233 | {lastStream.viewers} 234 | 235 | 236 | 237 | 238 | {lastStream.channelStatus} 239 | 240 | 241 | 242 | ); 243 | } 244 | return ( 245 | 246 | 247 | 252 | {itemColumn.name} 253 | {itemColumn.channelsText} 254 | 259 | 260 | {roomsLine} 261 | 262 | ); 263 | } 264 | 265 | _onRefresh(){ 266 | bannerData=[]; 267 | quickButton=[]; 268 | columnData=[]; 269 | this.getRemoteData(); 270 | } 271 | 272 | 273 | generateRootView(){ 274 | let qb=[]; 275 | quickButton.forEach((item,index,arrays)=>{ 276 | qb.push( 277 | 278 | ); 279 | }); 280 | let cr=[]; 281 | columnData.forEach((item,index,arrays)=>{ 282 | cr.push(this.generateRoom(item)); 283 | }); 284 | return ( 285 | 286 | 290 | 291 | 298 | 302 | 303 | {qb} 304 | 305 | 306 | {cr} 307 | 308 | 309 | 310 | ); 311 | } 312 | 313 | render(){ 314 | let cp; 315 | switch (this.state.dataState){ 316 | case DataState.hasReached: 317 | cp = this.generateRootView(); 318 | break; 319 | default: 320 | cp=CommonComponent.renderLoadingView(); 321 | break; 322 | } 323 | return cp; 324 | } 325 | } 326 | 327 | let styles=StyleSheet.create({ 328 | container:{ 329 | flex:1, 330 | justifyContent: 'center', 331 | alignItems: 'center', 332 | backgroundColor: '#F5FCFF' 333 | } 334 | }); -------------------------------------------------------------------------------- /FirstProject/appComponent/PtrFrameLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | 'use strict'; 5 | 6 | const React = require('React'); 7 | const ReactNative = require('ReactNative'); 8 | const requireNativeComponent = require('requireNativeComponent'); 9 | const View = require('View'); 10 | const Text = require('Text'); 11 | const Dimensions=require('Dimensions'); 12 | const deviceWidth = Dimensions.get('window').width; 13 | const ScrollView =require('ScrollView'); 14 | var UIManager = require('UIManager'); 15 | const PK_REF_KEY="pk_ref_key"; 16 | const PtrFrameLayout =React.createClass({ 17 | propTypes: { 18 | ...View.propTypes, 19 | }, 20 | 21 | generatedContent:function () { 22 | return ( 23 | 24 | {this.props.children} 25 | 26 | ); 27 | }, 28 | stopRefresh:function () { 29 | UIManager.dispatchViewManagerCommand( 30 | this.getPluImageHandle(), 31 | 1, 32 | null 33 | ); 34 | }, 35 | getPluImageHandle: function() { 36 | return ReactNative.findNodeHandle(this.refs[PK_REF_KEY]); 37 | }, 38 | render:function () { 39 | return ( 40 | { 43 | this.props.doRefresh&&this.props.doRefresh(); 44 | }} 45 | {...this.props} > 46 | {this.generatedContent()} 47 | 48 | ); 49 | } 50 | }); 51 | 52 | let AndroidPtrFrameLayout=requireNativeComponent('PtrFrameLayout',PtrFrameLayout,{}); 53 | module.exports=PtrFrameLayout; -------------------------------------------------------------------------------- /FirstProject/appComponent/RoundedImageView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | 'use strict'; 5 | 6 | import { PropTypes } from 'react'; 7 | import { requireNativeComponent, View } from 'react-native'; 8 | 9 | var iface = { 10 | name: 'RoundImageView', 11 | propTypes: { 12 | ...View.propTypes, 13 | url: PropTypes.string, 14 | }, 15 | }; 16 | 17 | module.exports = requireNativeComponent('AndroidRoundImage', iface); -------------------------------------------------------------------------------- /FirstProject/appComponent/Routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | 'use strict'; 5 | import React, { Component } from 'react'; 6 | import { 7 | Navigator, 8 | TouchableOpacity, 9 | StyleSheet, 10 | PixelRatio, 11 | Text, 12 | TextInput, 13 | View, 14 | BackAndroid, 15 | } from 'react-native'; 16 | import HomePage from './HomePage'; 17 | import Constants from './Constants'; 18 | import EntPage from './EntPage'; 19 | const routes = { 20 | navigator(initialRoute){ 21 | return ( 22 | { 26 | if(route.sceneConfig){ 27 | return route.sceneConfig; 28 | } 29 | return Navigator.SceneConfigs.FloatFromRight; 30 | }} 31 | tabLabel={this._tabObjForRoute(initialRoute)} 32 | /> 33 | ); 34 | }, 35 | _tabObjForRoute(routeName){ 36 | let tab=Constants.TAB_ARRAYS[0]; 37 | switch (routeName){ 38 | case 'tab_1': 39 | tab=Constants.TAB_ARRAYS[0]; 40 | break; 41 | case 'tab_2': 42 | tab=Constants.TAB_ARRAYS[1]; 43 | break; 44 | case 'tab_3': 45 | tab=Constants.TAB_ARRAYS[2]; 46 | break; 47 | case 'tab_4': 48 | tab=Constants.TAB_ARRAYS[3]; 49 | break; 50 | } 51 | return tab; 52 | }, 53 | renderScene(route,navigator){ 54 | BackAndroid.addEventListener('hardwareBackPress', () => { 55 | if (navigator && navigator.getCurrentRoutes().length > 1) { 56 | navigator.pop(); 57 | return true; 58 | } 59 | return false; 60 | }); 61 | switch (route.id){ 62 | case 'tab_1': 63 | return ; 64 | case 'tab_2': 65 | return ( 66 | 67 | 游戏 68 | 69 | ); 70 | case 'tab_3': 71 | return ( 72 | 73 | 随拍 74 | 75 | ); 76 | case 'tab_4': 77 | return ; 78 | default: 79 | return null; 80 | } 81 | } 82 | }; 83 | 84 | module.exports=routes; -------------------------------------------------------------------------------- /FirstProject/appComponent/TabBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/13. 3 | */ 4 | 'use strict'; 5 | 6 | import React, { Component } from 'react'; 7 | import { 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | TouchableOpacity 13 | } from 'react-native'; 14 | 15 | const propTypes = { 16 | goToPage: React.PropTypes.func, 17 | activeTab: React.PropTypes.number, 18 | tabs: React.PropTypes.array 19 | }; 20 | 21 | class TabBar extends Component{ 22 | renderTabOption(tab,page){ 23 | var isTabActive = this.props.activeTab === page; 24 | const tabImg=isTabActive ? tab.selected : tab.normal; 25 | const tabName=tab.name; 26 | return ( 27 | this.props.goToPage(page)} 30 | key={tabName} 31 | > 32 | 33 | 38 | {tabName} 39 | 40 | 41 | ); 42 | } 43 | 44 | render(){ 45 | return ( 46 | 47 | {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))} 48 | 49 | ); 50 | } 51 | } 52 | let styles = StyleSheet.create({ 53 | tab: { 54 | flex: 1, 55 | alignItems: 'center', 56 | justifyContent: 'center', 57 | }, 58 | itemImage:{ 59 | width:22, 60 | height:22 61 | }, 62 | itemText:{ 63 | fontSize:12, 64 | marginTop:4 65 | } 66 | }); 67 | 68 | TabBar.propTypes = propTypes; 69 | export default TabBar; -------------------------------------------------------------------------------- /FirstProject/appComponent/Toolbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lijie on 16/7/12. 3 | */ 4 | 'use strict'; 5 | 6 | import React, { Component } from 'react'; 7 | import { 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | Dimensions 13 | } from 'react-native'; 14 | 15 | export default class Toolbar extends Component { 16 | 17 | render(){ 18 | let tabName=this.props.tabArray[this.props.selectedTab].name; 19 | return ( 20 | 21 | 22 | 27 | 28 | 29 | {tabName} 30 | 31 | 36 | 41 | 42 | 43 | ); 44 | } 45 | } 46 | 47 | let styles=StyleSheet.create({ 48 | container:{ 49 | height:50, 50 | backgroundColor:'#FFFFFF', 51 | flexDirection:'row', 52 | width:Dimensions.get('window').width, 53 | alignItems:'center', 54 | elevation:1 55 | }, 56 | roundView:{ 57 | flexDirection:'row', 58 | width:50, 59 | alignItems:'center', 60 | justifyContent:'center', 61 | } 62 | }); 63 | 64 | -------------------------------------------------------------------------------- /FirstProject/img/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/img/ic_launcher.png -------------------------------------------------------------------------------- /FirstProject/index.android.bundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/FirstProject/index.android.bundle.meta -------------------------------------------------------------------------------- /FirstProject/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | import ToolBar from './appComponent/Toolbar'; 16 | const Routes=require('./appComponent/Routes'); 17 | const ScrollableTabView = require('react-native-scrollable-tab-view'); 18 | import TabBar from './appComponent/TabBar'; 19 | import Constants from './appComponent/Constants'; 20 | import CodePush from 'react-native-code-push'; 21 | class FirstProject extends Component { 22 | 23 | // 构造 24 | constructor(props) { 25 | super(props); 26 | // 初始状态 27 | this.state = { 28 | selectedTab:0 29 | }; 30 | this._onTabChanged=this._onTabChanged.bind(this); 31 | } 32 | 33 | _onTabChanged(index){ 34 | if (this.state.selectedTab!==index.i){ 35 | this.setState({ 36 | selectedTab:index.i 37 | }); 38 | } 39 | } 40 | 41 | componentWillMount() { 42 | CodePush.sync({ 43 | deploymentKey: 'm-riu3kK1__kGboK4WPIwBYs7ZwzEygDCEa5e', 44 | updateDialog: { 45 | optionalIgnoreButtonLabel: '稍后', 46 | optionalInstallButtonLabel: '后台更新', 47 | optionalUpdateMessage: '是否更新?---', 48 | title: '更新提示' 49 | }, 50 | installMode: CodePush.InstallMode.IMMEDIATE 51 | }); 52 | } 53 | 54 | render() { 55 | return ( 56 | 57 | 58 | } 60 | tabBarPosition={'bottom'} 61 | locked={true} 62 | onChangeTab={this._onTabChanged} 63 | initialPage={0} 64 | > 65 | {Routes.navigator('tab_1')} 66 | {Routes.navigator('tab_2')} 67 | {Routes.navigator('tab_3')} 68 | {Routes.navigator('tab_4')} 69 | 70 | 71 | ); 72 | } 73 | } 74 | 75 | const styles = StyleSheet.create({ 76 | container: { 77 | flex: 1, 78 | backgroundColor: '#F1F1F1' 79 | } 80 | }); 81 | 82 | AppRegistry.registerComponent('FirstProject', () => FirstProject); 83 | -------------------------------------------------------------------------------- /FirstProject/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | class FirstProject extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native! 21 | 22 | 23 | To get started, edit index.ios.js 24 | 25 | 26 | Press Cmd+R to reload,{'\n'} 27 | Cmd+D or shake for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('FirstProject', () => FirstProject); 54 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject.xcodeproj/xcshareddata/xcschemes/FirstProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTBundleURLProvider.h" 13 | #import "RCTRootView.h" 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | [[RCTBundleURLProvider sharedSettings] setDefaults]; 22 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 23 | 24 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 25 | moduleName:@"FirstProject" 26 | initialProperties:nil 27 | launchOptions:launchOptions]; 28 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 29 | 30 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 31 | UIViewController *rootViewController = [UIViewController new]; 32 | rootViewController.view = rootView; 33 | self.window.rootViewController = rootViewController; 34 | [self.window makeKeyAndVisible]; 35 | return YES; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSTemporaryExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProject/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProjectTests/FirstProjectTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface FirstProjectTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation FirstProjectTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /FirstProject/ios/FirstProjectTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /FirstProject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FirstProject", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "15.2.1", 10 | "react-native": "^0.29.0", 11 | "react-native-banner": "^0.1.0", 12 | "react-native-code-push": "^1.13.4-beta", 13 | "react-native-scrollable-tab-view": "^0.5.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReactNativeSimpleSource -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.android.js 5 | 6 | # Ignore templates with `@flow` in header 7 | .*/local-cli/generator.* 8 | 9 | # Ignore malformed json 10 | .*/node_modules/y18n/test/.*\.json 11 | 12 | [include] 13 | 14 | [libs] 15 | node_modules/react-native/Libraries/react-native/react-native-interface.js 16 | node_modules/react-native/flow 17 | flow/ 18 | 19 | [options] 20 | module.system=haste 21 | 22 | esproposal.class_static_fields=enable 23 | esproposal.class_instance_fields=enable 24 | 25 | experimental.strict_type_args=true 26 | 27 | munge_underscores=true 28 | 29 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 30 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 31 | 32 | suppress_type=$FlowIssue 33 | suppress_type=$FlowFixMe 34 | suppress_type=$FixMe 35 | 36 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 39 | 40 | [version] 41 | ^0.27.0 42 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/.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 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | *.iml 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | android/app/libs 41 | android/keystores/debug.keystore 42 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-hdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-hdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-mdpi/img_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-mdpi/img_icon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-mdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-mdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xxxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/drawable-xxxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/HotUpdate/index.android.bundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/HotUpdate/index.android.bundle.meta -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/BUCK: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # To learn about Buck see [Docs](https://buckbuild.com/). 4 | # To run your application with Buck: 5 | # - install Buck 6 | # - `npm start` - to start the packager 7 | # - `cd android` 8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US` 9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 10 | # - `buck install -r android/app` - compile, install and run application 11 | # 12 | 13 | lib_deps = [] 14 | for jarfile in glob(['libs/*.jar']): 15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) 16 | lib_deps.append(':' + name) 17 | prebuilt_jar( 18 | name = name, 19 | binary_jar = jarfile, 20 | ) 21 | 22 | for aarfile in glob(['libs/*.aar']): 23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) 24 | lib_deps.append(':' + name) 25 | android_prebuilt_aar( 26 | name = name, 27 | aar = aarfile, 28 | ) 29 | 30 | android_library( 31 | name = 'all-libs', 32 | exported_deps = lib_deps 33 | ) 34 | 35 | android_library( 36 | name = 'app-code', 37 | srcs = glob([ 38 | 'src/main/java/**/*.java', 39 | ]), 40 | deps = [ 41 | ':all-libs', 42 | ':build_config', 43 | ':res', 44 | ], 45 | ) 46 | 47 | android_build_config( 48 | name = 'build_config', 49 | package = 'com.bundleupdateproject', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.bundleupdateproject', 56 | ) 57 | 58 | android_binary( 59 | name = 'app', 60 | package_type = 'debug', 61 | manifest = 'src/main/AndroidManifest.xml', 62 | keystore = '//android/keystores:debug', 63 | deps = [ 64 | ':app-code', 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"] 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = false 84 | 85 | android { 86 | compileSdkVersion 23 87 | buildToolsVersion "23.0.1" 88 | 89 | defaultConfig { 90 | applicationId "com.bundleupdateproject" 91 | minSdkVersion 16 92 | targetSdkVersion 22 93 | versionCode 1 94 | versionName "1.0" 95 | ndk { 96 | abiFilters "armeabi-v7a", "x86" 97 | } 98 | } 99 | splits { 100 | abi { 101 | reset() 102 | enable enableSeparateBuildPerCPUArchitecture 103 | universalApk false // If true, also generate a universal APK 104 | include "armeabi-v7a", "x86" 105 | } 106 | } 107 | buildTypes { 108 | release { 109 | minifyEnabled enableProguardInReleaseBuilds 110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 111 | } 112 | } 113 | // applicationVariants are e.g. debug, release 114 | applicationVariants.all { variant -> 115 | variant.outputs.each { output -> 116 | // For each separate APK per architecture, set a unique version code as described here: 117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 118 | def versionCodes = ["armeabi-v7a":1, "x86":2] 119 | def abi = output.getFilter(OutputFile.ABI) 120 | if (abi != null) { // null for the universal-debug, universal-release variants 121 | output.versionCodeOverride = 122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 123 | } 124 | } 125 | } 126 | } 127 | 128 | dependencies { 129 | compile fileTree(include: ['*.jar'], dir: 'libs') 130 | compile 'com.android.support:appcompat-v7:23.0.1' 131 | compile 'io.reactivex:rxjava:1.1.2' 132 | compile 'io.reactivex:rxandroid:1.1.0' 133 | compile 'com.orhanobut:logger:1.15' 134 | // From node_modules 135 | compile project(':update') 136 | } 137 | 138 | // Run this once to be able to run the application with BUCK 139 | // puts all compile dependencies into folder libs for BUCK to use 140 | task copyDownloadableDepsToLibs(type: Copy) { 141 | from configurations.compile 142 | into 'libs' 143 | } 144 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # okhttp 54 | 55 | -keepattributes Signature 56 | -keepattributes *Annotation* 57 | -keep class okhttp3.** { *; } 58 | -keep interface okhttp3.** { *; } 59 | -dontwarn okhttp3.** 60 | 61 | # okio 62 | 63 | -keep class sun.misc.Unsafe { *; } 64 | -dontwarn java.nio.file.* 65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 66 | -dontwarn okio.** 67 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-hdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-hdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-mdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-mdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xxxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/drawable-xxxhdpi/node_modules_reactnative_libraries_customcomponents_navigationexperimental_assets_backicon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/index.android.bundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/assets/HotUpdate/index.android.bundle.meta -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/java/com/bundleupdateproject/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bundleupdateproject; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "BundleUpdateProject"; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/java/com/bundleupdateproject/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.bundleupdateproject; 2 | 3 | import android.app.Application; 4 | 5 | import com.example.update.UpdatePush; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | import javax.annotation.Nullable; 15 | 16 | public class MainApplication extends Application implements ReactApplication { 17 | 18 | 19 | @Override 20 | public void onCreate() { 21 | super.onCreate(); 22 | new UpdatePush(this); 23 | } 24 | 25 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 26 | @Override 27 | protected boolean getUseDeveloperSupport() { 28 | return false; 29 | } 30 | 31 | @Override 32 | protected List getPackages() { 33 | return Arrays.asList( 34 | new MainReactPackage() 35 | ); 36 | } 37 | 38 | 39 | @Nullable 40 | @Override 41 | protected String getJSBundleFile() { 42 | return UpdatePush.getJsBundle(); 43 | } 44 | }; 45 | 46 | @Override 47 | public ReactNativeHost getReactNativeHost() { 48 | return mReactNativeHost; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/java/com/bundleupdateproject/WelcomeActivity.java: -------------------------------------------------------------------------------- 1 | package com.bundleupdateproject; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.view.WindowManager; 9 | 10 | import com.example.update.BundleUpdateCallBack; 11 | import com.example.update.UpdatePush; 12 | import com.orhanobut.logger.Logger; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import rx.Observable; 17 | import rx.android.schedulers.AndroidSchedulers; 18 | import rx.functions.Action1; 19 | import rx.schedulers.Schedulers; 20 | 21 | 22 | /** 23 | * Created by lijie on 16/7/18. 24 | */ 25 | public class WelcomeActivity extends Activity { 26 | 27 | private long time_load;//加载时间 28 | 29 | private static int JUMP_TIME = 1000 * 3;//开屏启动时间 30 | 31 | private boolean isBundleMandatory;//检查bundle版本是否为强制更新版 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | time_load = System.currentTimeMillis(); 37 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {//4.4之下 38 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 39 | } 40 | setContentView(R.layout.activity_welcome); 41 | UpdatePush.checkRemoteBundleInfo(new BundleUpdateCallBack() { 42 | @Override 43 | public void onBundleMandatory(boolean isMandatory) { 44 | isBundleMandatory=isMandatory; 45 | if (!isMandatory){ //强制更新的版本 46 | jump(); 47 | } 48 | } 49 | 50 | @Override 51 | public void onReceiverByte(long receiverByte) { 52 | Log.d("info","receiverByte--"+receiverByte); 53 | } 54 | 55 | @Override 56 | public void onBundleUpdateFinished() { 57 | if (isBundleMandatory){ 58 | jump(); 59 | } 60 | } 61 | }); 62 | } 63 | 64 | private void jump(){ 65 | time_load = System.currentTimeMillis() - time_load; 66 | Logger.d("启动APP与访问接口耗时..."+time_load); 67 | long time_delayed = JUMP_TIME - time_load;//需要延迟加载的时间,防止二次启动过快 68 | Logger.d("延迟跳转时间:"+time_delayed); 69 | if (time_delayed < 0) time_delayed = 0; 70 | Observable.timer(time_delayed, TimeUnit.MILLISECONDS).observeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() { 71 | @Override 72 | public void call(Long aLong) { 73 | startActivity(new Intent(WelcomeActivity.this,MainActivity.class)); 74 | } 75 | }); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/layout/activity_welcome.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 29 | 30 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xhdpi/bg_welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xhdpi/bg_welcome.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | BundleUpdateProject 3 | 4 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.0.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jul 19 10:30:58 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'BundleUpdateProject' 2 | 3 | include ':app', ':update' 4 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.facebook.react:react-native:+' 23 | } 24 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/lijie/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/androidTest/java/com/example/update/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/BundleUpdateCallBack.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | /** 4 | * Created by lijie on 16/7/18. 5 | */ 6 | public interface BundleUpdateCallBack { 7 | void onBundleMandatory(boolean isMandatory); 8 | 9 | void onReceiverByte(long receiverByte); 10 | 11 | void onBundleUpdateFinished(); 12 | } 13 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.io.PrintWriter; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipInputStream; 13 | 14 | public class FileUtils { 15 | 16 | private static final int WRITE_BUFFER_SIZE = 1024 * 8; 17 | 18 | 19 | public static void copyDirectoryContents(String sourceDirectoryPath, String destinationDirectoryPath) throws IOException { 20 | File sourceDir = new File(sourceDirectoryPath); 21 | File destDir = new File(destinationDirectoryPath); 22 | if (!destDir.exists()) { 23 | destDir.mkdir(); 24 | } 25 | 26 | for (File sourceFile : sourceDir.listFiles()) { 27 | if (sourceFile.isDirectory()) { 28 | copyDirectoryContents( 29 | UpdateUtils.appendPathComponent(sourceDirectoryPath, sourceFile.getName()), 30 | UpdateUtils.appendPathComponent(destinationDirectoryPath, sourceFile.getName())); 31 | } else { 32 | File destFile = new File(destDir, sourceFile.getName()); 33 | FileInputStream fromFileStream = null; 34 | BufferedInputStream fromBufferedStream = null; 35 | FileOutputStream destStream = null; 36 | byte[] buffer = new byte[WRITE_BUFFER_SIZE]; 37 | try { 38 | fromFileStream = new FileInputStream(sourceFile); 39 | fromBufferedStream = new BufferedInputStream(fromFileStream); 40 | destStream = new FileOutputStream(destFile); 41 | int bytesRead; 42 | while ((bytesRead = fromBufferedStream.read(buffer)) > 0) { 43 | destStream.write(buffer, 0, bytesRead); 44 | } 45 | } finally { 46 | try { 47 | if (fromFileStream != null) fromFileStream.close(); 48 | if (fromBufferedStream != null) fromBufferedStream.close(); 49 | if (destStream != null) destStream.close(); 50 | } catch (IOException e) { 51 | throw new RuntimeException("Error closing IO resources.", e); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | public static void deleteDirectory(File directory) { 59 | if (directory.exists()) { 60 | File[] files = directory.listFiles(); 61 | if (files != null) { 62 | for (File file : files) { 63 | if(file.isDirectory()) { 64 | deleteDirectory(file); 65 | } 66 | else { 67 | file.delete(); 68 | } 69 | } 70 | } 71 | } 72 | directory.delete(); 73 | } 74 | 75 | public static void deleteDirectoryAtPath(String directoryPath) { 76 | deleteDirectory(new File(directoryPath)); 77 | } 78 | 79 | public static void deleteFileAtPathSilently(String path) { 80 | deleteFileOrFolderSilently(new File(path)); 81 | } 82 | 83 | public static void deleteFileOrFolderSilently(File file) { 84 | if (file.isDirectory()) { 85 | File[] files = file.listFiles(); 86 | for (File fileEntry : files) { 87 | if (fileEntry.isDirectory()) { 88 | deleteFileOrFolderSilently(fileEntry); 89 | } else { 90 | if (!file.delete()) { 91 | fileEntry.delete(); 92 | } 93 | } 94 | } 95 | } 96 | 97 | if (!file.delete()) { 98 | // CodePushUtils.log("Error deleting file " + file.getName()); 99 | } 100 | } 101 | /**判断文件是否存在*/ 102 | public static boolean fileAtPathExists(String filePath) { 103 | return new File(filePath).exists(); 104 | } 105 | 106 | public static void moveFile(File fileToMove, String newFolderPath, String newFileName) { 107 | File newFolder = new File(newFolderPath); 108 | if (!newFolder.exists()) { 109 | newFolder.mkdirs(); 110 | } 111 | 112 | File newFilePath = new File(newFolderPath, newFileName); 113 | if (!fileToMove.renameTo(newFilePath)) { 114 | // throw new CodePushUnknownException("Unable to move file from " + 115 | // fileToMove.getAbsolutePath() + " to " + newFilePath.getAbsolutePath() + "."); 116 | } 117 | } 118 | 119 | /**从指定路径文件 读取里面内容*/ 120 | public static String readFileToString(String filePath) throws IOException { 121 | FileInputStream fin = null; 122 | BufferedReader reader = null; 123 | try { 124 | File fl = new File(filePath); 125 | fin = new FileInputStream(fl); 126 | reader = new BufferedReader(new InputStreamReader(fin)); 127 | StringBuilder sb = new StringBuilder(); 128 | String line = null; 129 | while ((line = reader.readLine()) != null) { 130 | sb.append(line).append("\n"); 131 | } 132 | 133 | return sb.toString(); 134 | } finally { 135 | if (reader != null) reader.close(); 136 | if (fin != null) fin.close(); 137 | } 138 | } 139 | 140 | public static void unzipFile(File zipFile, String destination) throws IOException { 141 | FileInputStream fileStream = null; 142 | BufferedInputStream bufferedStream = null; 143 | ZipInputStream zipStream = null; 144 | try { 145 | fileStream = new FileInputStream(zipFile); 146 | bufferedStream = new BufferedInputStream(fileStream); 147 | zipStream = new ZipInputStream(bufferedStream); 148 | ZipEntry entry; 149 | 150 | File destinationFolder = new File(destination); 151 | if (destinationFolder.exists()) { 152 | deleteDirectory(destinationFolder); 153 | } 154 | 155 | destinationFolder.mkdirs(); 156 | 157 | byte[] buffer = new byte[WRITE_BUFFER_SIZE]; 158 | while ((entry = zipStream.getNextEntry()) != null) { 159 | String fileName = entry.getName(); 160 | File file = new File(destinationFolder, fileName); 161 | if (entry.isDirectory()) { 162 | file.mkdirs(); 163 | } else { 164 | File parent = file.getParentFile(); 165 | if (!parent.exists()) { 166 | parent.mkdirs(); 167 | } 168 | 169 | FileOutputStream fout = new FileOutputStream(file); 170 | try { 171 | int numBytesRead; 172 | while ((numBytesRead = zipStream.read(buffer)) != -1) { 173 | fout.write(buffer, 0, numBytesRead); 174 | } 175 | } finally { 176 | fout.close(); 177 | } 178 | } 179 | long time = entry.getTime(); 180 | if (time > 0) { 181 | file.setLastModified(time); 182 | } 183 | } 184 | } finally { 185 | try { 186 | if (zipStream != null) zipStream.close(); 187 | if (bufferedStream != null) bufferedStream.close(); 188 | if (fileStream != null) fileStream.close(); 189 | } catch (IOException e) { 190 | // throw new CodePushUnknownException("Error closing IO resources.", e); 191 | } 192 | } 193 | } 194 | 195 | public static void writeStringToFile(String content, String filePath) throws IOException { 196 | PrintWriter out = null; 197 | try { 198 | out = new PrintWriter(filePath); 199 | out.print(content); 200 | } finally { 201 | if (out != null) out.close(); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/UpdateConstants.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | /** 4 | * Created by lijie on 16/7/16. 5 | */ 6 | public class UpdateConstants { 7 | 8 | public static final String ASSETS_BUNDLE_PREFIX = "assets://HotUpdate/"; 9 | public static final String DEFAULT_JS_BUNDLE_NAME = "index.android.bundle"; 10 | /**存放 更新文件的文件夹名字*/ 11 | public static final String PLU_RN_FOLDER_PREFIX = "PluRN"; 12 | /**存放 当前与上一版本的 hash值*/ 13 | public static final String STATUS_FILE = "status.json"; 14 | /**当前应该显示文件的key*/ 15 | public static final String CURRENT_PACKAGE_KEY = "currentPackage"; 16 | 17 | public static final String PREVIOUS_PACKAGE_KEY = "previousPackage"; 18 | 19 | /**当前版本包的信息存放json*/ 20 | public static final String PACKAGE_FILE_NAME = "app.json"; 21 | 22 | public static final String DOWNLOAD_FILE_NAME = "download.zip"; 23 | 24 | public static final int DOWNLOAD_BUFFER_SIZE = 1024 * 256; 25 | 26 | public static final String UNZIPPED_FOLDER_NAME = "unzipped"; 27 | 28 | 29 | /**bundle文件的相对路径key*/ 30 | public static final String RELATIVE_BUNDLE_PATH_KEY = "bundlePath"; 31 | 32 | public static final String PACKAGE_APP_VERSION="appVersion"; 33 | public static final String PACKAGE_APP_LABEL="label"; 34 | /**访问外网的HOST*/ 35 | private static final String HOST="http://git.oschina.net/dshihouzaishuo/testRnVersion/raw/master/"; 36 | /**检查最新的版本文件*/ 37 | public static String getCheckLastestUrl(String appVersion){ 38 | return HOST+appVersion+".json"; 39 | } 40 | public static final String CHECK_INFO_LABEL="label"; 41 | public static final String CHECK_INFO_DOWNLOAD_URL="downloadUrl"; 42 | public static final String CHECK_INFO_ISMANDOTORY="isMandatory"; 43 | public static final String CHECK_INFO_PACKAGEHASH="packageHash"; 44 | public static final String CHECK_INFO_FAILED="isFailed"; 45 | /** 46 | * 打包命令:react-native bundle --assets-dest HotUpdate --bundle-output HotUpdate/index.android.bundle --dev false --entry-file index.android.js --platform android 47 | */ 48 | } 49 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/UpdateManager.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.io.BufferedInputStream; 11 | import java.io.BufferedOutputStream; 12 | import java.io.File; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.net.HttpURLConnection; 16 | import java.net.MalformedURLException; 17 | import java.net.URL; 18 | import java.nio.ByteBuffer; 19 | import java.util.HashMap; 20 | 21 | /** 22 | * Created by lijie on 16/7/16. 23 | */ 24 | public class UpdateManager { 25 | 26 | 27 | private String mDocumentsDirectory; 28 | 29 | public UpdateManager(String documentsDirectory){ 30 | this.mDocumentsDirectory=documentsDirectory; 31 | } 32 | private String getDocumentsDirectory() { 33 | return mDocumentsDirectory; 34 | } 35 | 36 | /**存放 升级版本的文件夹*/ 37 | private String getUpdateFilePath(){ 38 | String updateFilePath=UpdateUtils.appendPathComponent(getDocumentsDirectory(),UpdateConstants.PLU_RN_FOLDER_PREFIX); 39 | return updateFilePath; 40 | } 41 | 42 | /**获取 状态文件的路径*/ 43 | private String getStatusFilePath(){ 44 | return UpdateUtils.appendPathComponent(getUpdateFilePath(),UpdateConstants.STATUS_FILE); 45 | } 46 | 47 | /**获取 更新配置文件的WritableMap对象 */ 48 | public HashMap getCurrentPackageInfo(){ 49 | String statusFilePath=getStatusFilePath(); 50 | if (FileUtils.fileAtPathExists(statusFilePath)){ 51 | try { 52 | return UpdateUtils.getWritableMapFromFile(statusFilePath); 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | return new HashMap(); 58 | } 59 | 60 | /**根据文件夹名字获取绝对路径*/ 61 | public String getPackageFolderPath(String packageHash){ 62 | return UpdateUtils.appendPathComponent(getUpdateFilePath(),packageHash); 63 | } 64 | 65 | /**获取当前 应该显示的更新文件 路径*/ 66 | public String getCurrentPackageFolderPath(){ 67 | HashMap info=getCurrentPackageInfo(); 68 | String packageHash=UpdateUtils.tryGetString(info,UpdateConstants.CURRENT_PACKAGE_KEY); 69 | if (packageHash!=null){ 70 | return getPackageFolderPath(packageHash); 71 | } 72 | return null; 73 | } 74 | 75 | /**获取配置文件中当前更新文件的Hash值*/ 76 | public String getCurrentPackageHash(){ 77 | HashMap info=getCurrentPackageInfo(); 78 | return UpdateUtils.tryGetString(info,UpdateConstants.CURRENT_PACKAGE_KEY); 79 | } 80 | 81 | 82 | /**返回当前版本包的配置信息 app.json*/ 83 | public HashMap getCurrentPackage(){ 84 | String packageHash=getCurrentPackageHash(); 85 | if (packageHash==null){ 86 | return null; 87 | } 88 | return getPackage(packageHash); 89 | } 90 | /**根据版本号hash值返回版本包的配置信息 app.json */ 91 | public HashMap getPackage(String packageHash){ 92 | String folderPath=getPackageFolderPath(packageHash); 93 | String packageFilePath=UpdateUtils.appendPathComponent(folderPath,UpdateConstants.PACKAGE_FILE_NAME); 94 | if (!FileUtils.fileAtPathExists(packageFilePath)){ 95 | return null; 96 | } 97 | try { 98 | return UpdateUtils.getWritableMapFromFile(packageFilePath); 99 | } catch (IOException e) { 100 | return null; 101 | } 102 | } 103 | 104 | public String getCurrentPackageBundlePath(String bundleFileName){ 105 | String packageFolder=getCurrentPackageFolderPath(); 106 | if (packageFolder==null){ 107 | return null; 108 | } 109 | HashMap currentPackage=getCurrentPackage(); 110 | if (currentPackage==null){ 111 | return null; 112 | } 113 | String relativeBundlePath=UpdateUtils.tryGetString(currentPackage,UpdateConstants.RELATIVE_BUNDLE_PATH_KEY); 114 | if (relativeBundlePath==null){ 115 | return UpdateUtils.appendPathComponent(packageFolder,bundleFileName); 116 | } 117 | else { 118 | return UpdateUtils.appendPathComponent(packageFolder,relativeBundlePath); 119 | } 120 | } 121 | 122 | 123 | public void rollBackPreviousPackage(){ 124 | // try { 125 | // Log.e("info","正在执行回滚操作....."); 126 | // //将status.json 文件的 currentPackageHash删除, 用 previousPackageHash 当做currentPackageHash 127 | // String statusContent=FileUtils.readFileToString(getStatusFilePath()); 128 | // JSONObject jsonObject=new JSONObject(statusContent); 129 | // String previousPackageHash=jsonObject.getString(UpdateConstants.PREVIOUS_PACKAGE_KEY); 130 | // String currentPackageHash=jsonObject.getString(UpdateConstants.CURRENT_PACKAGE_KEY); 131 | // Log.e("info","正在执行回滚操作.....1"); 132 | //// Log.e("info",previousPackageHash+"-----previousPackageHash----"); 133 | // 134 | // if (TextUtils.isEmpty(previousPackageHash)){ //没有可回退的版本 135 | // FileUtils.writeStringToFile("",getStatusFilePath()); 136 | // Log.e("info","正在执行回滚操作.....2"); 137 | // } 138 | // else{ 139 | // jsonObject.remove(UpdateConstants.PREVIOUS_PACKAGE_KEY); 140 | // jsonObject.put(UpdateConstants.CURRENT_PACKAGE_KEY,previousPackageHash); 141 | // FileUtils.writeStringToFile(jsonObject.toString(),getStatusFilePath()); 142 | // Log.e("info","正在执行回滚操作.....3"); 143 | // } 144 | // 145 | // //将出错的bundle 的标志设置为 failed:true 146 | // String folderPath=getPackageFolderPath(currentPackageHash); 147 | // String packageFilePath=UpdateUtils.appendPathComponent(folderPath,UpdateConstants.PACKAGE_FILE_NAME); 148 | // String appJsonContent=FileUtils.readFileToString(packageFilePath); 149 | // JSONObject appJsonObject=new JSONObject(appJsonContent); 150 | // appJsonObject.put(UpdateConstants.CHECK_INFO_FAILED,true); 151 | // FileUtils.writeStringToFile(appJsonObject.toString(),packageFilePath); 152 | // Log.e("info","正在执行回滚操作.....4"); 153 | // } catch (IOException e) { 154 | // e.printStackTrace(); 155 | // } catch (JSONException e) { 156 | // e.printStackTrace(); 157 | // } 158 | } 159 | 160 | /**写入appJson*/ 161 | private void saveAppJsonToSdCard(String appJson,File file){ 162 | if (FileUtils.fileAtPathExists(file.getAbsolutePath())){ 163 | file.delete(); 164 | } 165 | try { 166 | FileUtils.writeStringToFile(appJson,file.getAbsolutePath()); 167 | } catch (IOException e) { 168 | e.printStackTrace(); 169 | } 170 | } 171 | 172 | public void downloadBundleFile(String downloadUrlString,String packageHash,JSONObject appJson,BundleUpdateCallBack mBundleUpdateCallBack) throws IOException { 173 | HttpURLConnection connection = null; 174 | BufferedInputStream bin = null; 175 | FileOutputStream fos = null; 176 | BufferedOutputStream bout = null; 177 | File downloadFile = null; 178 | boolean isZip = false; 179 | 180 | try { 181 | URL downloadUrl = new URL(downloadUrlString); 182 | connection = (HttpURLConnection) (downloadUrl.openConnection()); 183 | connection.setRequestProperty("Accept-Encoding", "identity"); 184 | long totalBytes = connection.getContentLength(); 185 | long receivedBytes = 0; 186 | bin = new BufferedInputStream(connection.getInputStream()); 187 | File downloadFolder = new File(getUpdateFilePath()); 188 | downloadFolder.mkdirs(); 189 | downloadFile = new File(downloadFolder, UpdateConstants.DOWNLOAD_FILE_NAME); 190 | if (FileUtils.fileAtPathExists(downloadFile.getAbsolutePath())){ 191 | downloadFile.delete(); 192 | } 193 | fos = new FileOutputStream(downloadFile); 194 | bout = new BufferedOutputStream(fos, UpdateConstants.DOWNLOAD_BUFFER_SIZE); 195 | byte[] data = new byte[UpdateConstants.DOWNLOAD_BUFFER_SIZE]; 196 | byte[] header = new byte[4]; 197 | 198 | int numBytesRead = 0; 199 | while ((numBytesRead = bin.read(data, 0, UpdateConstants.DOWNLOAD_BUFFER_SIZE)) >= 0) { 200 | if (receivedBytes < 4) { 201 | for (int i = 0; i < numBytesRead; i++) { 202 | int headerOffset = (int)(receivedBytes) + i; 203 | if (headerOffset >= 4) { 204 | break; 205 | } 206 | header[headerOffset] = data[i]; 207 | } 208 | } 209 | receivedBytes += numBytesRead; 210 | bout.write(data, 0, numBytesRead); 211 | if (mBundleUpdateCallBack!=null){ 212 | mBundleUpdateCallBack.onReceiverByte(receivedBytes); 213 | } 214 | // progressCallback.call(new DownloadProgress(totalBytes, receivedBytes)); 215 | } 216 | if (mBundleUpdateCallBack!=null){ 217 | mBundleUpdateCallBack.onBundleUpdateFinished(); 218 | } 219 | if (totalBytes != receivedBytes) { 220 | Log.d("info","receivedBytes="+receivedBytes+",expected="+totalBytes); 221 | // totalBytes 需要服务端支持 Content-Length 222 | } 223 | isZip = ByteBuffer.wrap(header).getInt() == 0x504b0304; 224 | } catch (MalformedURLException e) { 225 | e.printStackTrace(); 226 | } catch (IOException e) { 227 | e.printStackTrace(); 228 | } finally { 229 | try { 230 | if (bout != null) bout.close(); 231 | if (fos != null) fos.close(); 232 | if (bin != null) bin.close(); 233 | if (connection != null) connection.disconnect(); 234 | } catch (IOException e) { 235 | throw new RuntimeException("Error closing IO resources.", e); 236 | } 237 | } 238 | if (isZip) { 239 | String newUpdateFolderPath=getPackageFolderPath(packageHash); 240 | String newUpdateMetadataPath = UpdateUtils.appendPathComponent(newUpdateFolderPath, UpdateConstants.PACKAGE_FILE_NAME); 241 | String unzippedFolderPath = getUnzippedFolderPath(); 242 | FileUtils.unzipFile(downloadFile, unzippedFolderPath); 243 | FileUtils.deleteFileOrFolderSilently(downloadFile); 244 | 245 | FileUtils.copyDirectoryContents(unzippedFolderPath, newUpdateFolderPath); 246 | FileUtils.deleteFileAtPathSilently(unzippedFolderPath); 247 | 248 | String relativeBundlePath = UpdateUtils.findJSBundleInUpdateContents(newUpdateFolderPath, UpdateConstants.DEFAULT_JS_BUNDLE_NAME); 249 | if (relativeBundlePath==null){ 250 | throw new RuntimeException("not found index.android.bundle"); 251 | } 252 | else{ 253 | //如果存在app.json 则删除 254 | if (FileUtils.fileAtPathExists(newUpdateMetadataPath)) { 255 | File metadataFileFromOldUpdate = new File(newUpdateMetadataPath); 256 | metadataFileFromOldUpdate.delete(); 257 | } 258 | try { 259 | //添加bundlePath 字段,标志index.android.bundle相对于app.json的路径 260 | appJson.put(UpdateConstants.RELATIVE_BUNDLE_PATH_KEY,relativeBundlePath); 261 | saveAppJsonToSdCard(appJson.toString(),new File(newUpdateMetadataPath)); 262 | updateStatusFile(packageHash); 263 | } catch (JSONException e) { 264 | e.printStackTrace(); 265 | } 266 | } 267 | } 268 | } 269 | 270 | private void updateStatusFile(String packageHash){ 271 | String statusFilePath=getStatusFilePath(); 272 | 273 | JSONObject jsonObject=new JSONObject(); 274 | try { 275 | jsonObject.put(UpdateConstants.CURRENT_PACKAGE_KEY,packageHash); 276 | } catch (JSONException e) { 277 | e.printStackTrace(); 278 | } 279 | //如果之前存在statusFile,则把之前的currentPackageHash,当previousPackageHash 280 | if (FileUtils.fileAtPathExists(statusFilePath)){ 281 | try { 282 | String preContent=FileUtils.readFileToString(statusFilePath); 283 | if (!TextUtils.isEmpty(preContent)){ 284 | JSONObject preJson=new JSONObject(preContent); 285 | String prePackageHash=preJson.getString(UpdateConstants.CURRENT_PACKAGE_KEY); 286 | jsonObject.put(UpdateConstants.PREVIOUS_PACKAGE_KEY,prePackageHash); 287 | } 288 | } catch (JSONException e) { 289 | e.printStackTrace(); 290 | } catch (IOException e) { 291 | e.printStackTrace(); 292 | } 293 | } 294 | try { 295 | FileUtils.writeStringToFile(jsonObject.toString(),statusFilePath); 296 | } catch (IOException e) { 297 | e.printStackTrace(); 298 | } 299 | } 300 | 301 | 302 | /**解压文件夹 data/data/xxx/file/PluRn/unzipped/ */ 303 | private String getUnzippedFolderPath() { 304 | return UpdateUtils.appendPathComponent(getUpdateFilePath(), UpdateConstants.UNZIPPED_FOLDER_NAME); 305 | } 306 | 307 | 308 | 309 | } 310 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/UpdatePush.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | 15 | import okhttp3.Call; 16 | import okhttp3.Callback; 17 | import okhttp3.OkHttpClient; 18 | import okhttp3.Request; 19 | import okhttp3.Response; 20 | 21 | /** 22 | * Created by lijie on 16/7/16. 23 | */ 24 | public class UpdatePush { 25 | 26 | private static UpdatePush mCurrentInstance; 27 | 28 | private Context mContext; 29 | 30 | private String mAppVersion; 31 | 32 | private UpdateManager mUpdateManager; 33 | 34 | public UpdatePush(Context context){ 35 | this.mContext=context; 36 | mUpdateManager=new UpdateManager(context.getFilesDir().getAbsolutePath()); 37 | PackageInfo pInfo = null; 38 | try { 39 | pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); 40 | mAppVersion = pInfo.versionName; 41 | } catch (PackageManager.NameNotFoundException e) { 42 | e.printStackTrace(); 43 | } 44 | mCurrentInstance=this; 45 | } 46 | 47 | 48 | public static String getJsBundle(){ 49 | if (mCurrentInstance==null){ 50 | throw new RuntimeException("should initialize this"); 51 | } 52 | return mCurrentInstance.getJsBundleFile(); 53 | } 54 | 55 | /**找到应该显示的版本号*/ 56 | public String getJsBundleFile(){ 57 | //放在asserts里面的bundle 58 | String binaryJsBundleUrl = UpdateConstants.ASSETS_BUNDLE_PREFIX + UpdateConstants.DEFAULT_JS_BUNDLE_NAME; 59 | //获取相应目录下的bundle 60 | String packageFilePath=mUpdateManager.getCurrentPackageBundlePath(UpdateConstants.DEFAULT_JS_BUNDLE_NAME); 61 | if (packageFilePath!=null){ 62 | HashMap packageMetadata = this.mUpdateManager.getCurrentPackage(); 63 | String packageAppVersion = UpdateUtils.tryGetString(packageMetadata, UpdateConstants.PACKAGE_APP_VERSION); 64 | if (mAppVersion.equals(packageAppVersion)){ 65 | return packageFilePath; 66 | } 67 | } 68 | // isUsedAssertsBundle=true; 69 | return binaryJsBundleUrl; 70 | } 71 | 72 | private OkHttpClient okHttpClient; 73 | OkHttpClient getOkHttpClient(){ 74 | if (okHttpClient==null){ 75 | okHttpClient=new OkHttpClient(); 76 | } 77 | return okHttpClient; 78 | } 79 | private BundleUpdateCallBack mBundleUpdateCallBack; 80 | 81 | private void checkUpdate(BundleUpdateCallBack bundleUpdateCallBack){ 82 | this.mBundleUpdateCallBack=bundleUpdateCallBack; 83 | String url=UpdateConstants.getCheckLastestUrl(mAppVersion); 84 | Log.d("info","查询更新bundle的地址.."+url); 85 | Request request=new Request.Builder().url(url).build(); 86 | Call call=getOkHttpClient().newCall(request); 87 | call.enqueue(new Callback() { 88 | @Override 89 | public void onFailure(Call call, IOException e) { 90 | } 91 | 92 | @Override 93 | public void onResponse(Call call, Response response) throws IOException { 94 | handleBundleInfo(response); 95 | } 96 | }); 97 | } 98 | 99 | /**检查版本号是否需要更新*/ 100 | public static void checkRemoteBundleInfo(BundleUpdateCallBack callBack){ 101 | if (mCurrentInstance==null){ 102 | throw new RuntimeException("mCurrentInstance is null"); 103 | } 104 | mCurrentInstance.checkUpdate(callBack); 105 | } 106 | 107 | public void rollBackCurrentPackage(){ 108 | mUpdateManager.rollBackPreviousPackage(); 109 | } 110 | 111 | private void handleBundleInfo(Response response){ 112 | if (response.isSuccessful()){ 113 | JSONObject jsonObject=null; 114 | try { 115 | jsonObject=new JSONObject(response.body().string()); 116 | String label=jsonObject.getString(UpdateConstants.CHECK_INFO_LABEL); 117 | if (label.equals("v0")){ //v0版本表示底包,不需要升级 118 | if (mBundleUpdateCallBack!=null){ 119 | mBundleUpdateCallBack.onBundleMandatory(false); 120 | mBundleUpdateCallBack=null; 121 | } 122 | return; 123 | } 124 | String downloadUrl=jsonObject.getString(UpdateConstants.CHECK_INFO_DOWNLOAD_URL); 125 | boolean isMandatory=jsonObject.getBoolean(UpdateConstants.CHECK_INFO_ISMANDOTORY); 126 | String packageHash=jsonObject.getString(UpdateConstants.CHECK_INFO_PACKAGEHASH); 127 | if (!TextUtils.isEmpty(label)){ 128 | if (mBundleUpdateCallBack!=null){ 129 | mBundleUpdateCallBack.onBundleMandatory(isMandatory); 130 | if (!isMandatory){ 131 | mBundleUpdateCallBack=null; 132 | } 133 | } 134 | String packageFilePath=mUpdateManager.getCurrentPackageBundlePath(UpdateConstants.DEFAULT_JS_BUNDLE_NAME); 135 | //确认文件是否存在 136 | if (packageFilePath!=null){ 137 | //找到app.json的配置信息 138 | HashMap packageMetadata = this.mUpdateManager.getCurrentPackage(); 139 | String packageAppVersion = UpdateUtils.tryGetString(packageMetadata, UpdateConstants.PACKAGE_APP_VERSION); 140 | String packageAppLabel=UpdateUtils.tryGetString(packageMetadata,UpdateConstants.PACKAGE_APP_LABEL); 141 | 142 | if (packageAppVersion.equals(mAppVersion)){ 143 | if (!packageAppLabel.equals(label)){ 144 | Log.d("info","bundle有新的版本可下载"); 145 | mUpdateManager.downloadBundleFile(downloadUrl,packageHash,jsonObject,mBundleUpdateCallBack); 146 | } 147 | else{ 148 | if (mBundleUpdateCallBack!=null){ 149 | mBundleUpdateCallBack.onBundleMandatory(false); 150 | } 151 | Log.d("info","bundle当前是最新版本"); 152 | } 153 | } 154 | else{ 155 | if (mBundleUpdateCallBack!=null){ 156 | mBundleUpdateCallBack.onBundleMandatory(false); 157 | } 158 | Log.d("info","该bundle版本不适用于该APP版本"); 159 | } 160 | } 161 | else{ 162 | Log.d("info","需要下载bundle"); 163 | mUpdateManager.downloadBundleFile(downloadUrl,packageHash,jsonObject,mBundleUpdateCallBack); 164 | } 165 | } 166 | } catch (JSONException e) { 167 | e.printStackTrace(); 168 | } catch (IOException e) { 169 | e.printStackTrace(); 170 | } 171 | } 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/java/com/example/update/UpdateUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | 4 | import org.json.JSONException; 5 | import org.json.JSONObject; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.util.HashMap; 10 | import java.util.Iterator; 11 | 12 | /** 13 | * Created by lijie on 16/7/16. 14 | */ 15 | public class UpdateUtils { 16 | 17 | /**根据key获取map的value值*/ 18 | public static String tryGetString(HashMap map, String key){ 19 | try { 20 | return (String) map.get(key); 21 | }catch (Exception e){ 22 | return null; 23 | } 24 | } 25 | 26 | /**获取文件绝对路径*/ 27 | public static String appendPathComponent(String basePath,String appendPathComponent){ 28 | return new File(basePath, appendPathComponent).getAbsolutePath(); 29 | } 30 | 31 | /**从指定路径中获取WritableMap*/ 32 | public static HashMap getWritableMapFromFile(String filePath) throws IOException { 33 | String content = FileUtils.readFileToString(filePath); 34 | try { 35 | JSONObject json=new JSONObject(content); 36 | return convertJsonObjectToWritable(json); 37 | } catch (JSONException e) { 38 | throw new RuntimeException("failed to parse json"); 39 | } 40 | } 41 | 42 | // /**将JsonArray对象转换成WritableArray*/ 43 | // public static HashMap convertJsonArrayToWritable(JSONArray jsonArr){ 44 | //// WritableArray arr= Arguments.createArray(); 45 | // HashMap arr=new HashMap(); 46 | // for (int i=0; i it=jsonObject.keys(); 80 | while (it.hasNext()){ 81 | String key=it.next(); 82 | Object obj=null; 83 | try { 84 | obj=jsonObject.get(key); 85 | } catch (JSONException e) { 86 | e.printStackTrace(); 87 | } 88 | if (obj instanceof String){ 89 | map.put(key,(String)obj); 90 | } 91 | else if(obj instanceof Boolean){ 92 | map.put(key,(Boolean)obj); 93 | } 94 | else if (obj instanceof Double){ 95 | map.put(key,(Double)obj); 96 | } 97 | else if (obj instanceof Integer){ 98 | map.put(key,(Integer)obj); 99 | } 100 | else if (obj ==null){ 101 | map.put(key,null); 102 | } 103 | else { 104 | throw new RuntimeException("Unrecognized object: " + obj); 105 | } 106 | } 107 | return map; 108 | } 109 | 110 | 111 | public static String findJSBundleInUpdateContents(String folderPath, String expectedFileName) { 112 | File folder = new File(folderPath); 113 | File[] folderFiles = folder.listFiles(); 114 | for (File file : folderFiles) { 115 | String fullFilePath = UpdateUtils.appendPathComponent(folderPath, file.getName()); 116 | if (file.isDirectory()) { 117 | String mainBundlePathInSubFolder = findJSBundleInUpdateContents(fullFilePath, expectedFileName); 118 | if (mainBundlePathInSubFolder != null) { 119 | return UpdateUtils.appendPathComponent(file.getName(), mainBundlePathInSubFolder); 120 | } 121 | } else { 122 | String fileName = file.getName(); 123 | if (fileName.equals(expectedFileName)) { 124 | return fileName; 125 | } 126 | } 127 | } 128 | return null; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Update 3 | 4 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/android/update/src/test/java/com/example/update/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.update; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq3061280/ReactNativeSimpleSource/2b38f4bd8bca5c11f70b2f9ea8633c3405dd36d6/testUpdateRn/BundleUpdateProject/img/icon.png -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View, 13 | Image 14 | } from 'react-native'; 15 | 16 | class BundleUpdateProject extends Component { 17 | render() { 18 | return ( 19 | 20 | 21 | Welcome to React Native ! 22 | 23 | 28 | 29 | ); 30 | } 31 | } 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | flex: 1, 36 | justifyContent: 'center', 37 | alignItems: 'center', 38 | backgroundColor: '#F5FCFF', 39 | }, 40 | welcome: { 41 | fontSize: 20, 42 | textAlign: 'center', 43 | margin: 10, 44 | }, 45 | instructions: { 46 | textAlign: 'center', 47 | color: '#333333', 48 | marginBottom: 5, 49 | }, 50 | }); 51 | 52 | AppRegistry.registerComponent('BundleUpdateProject', () => BundleUpdateProject); 53 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | class BundleUpdateProject extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native! 21 | 22 | 23 | To get started, edit index.ios.js 24 | 25 | 26 | Press Cmd+R to reload,{'\n'} 27 | Cmd+D or shake for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('BundleUpdateProject', () => BundleUpdateProject); 54 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject.xcodeproj/xcshareddata/xcschemes/BundleUpdateProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTBundleURLProvider.h" 13 | #import "RCTRootView.h" 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | [[RCTBundleURLProvider sharedSettings] setDefaults]; 22 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 23 | 24 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 25 | moduleName:@"BundleUpdateProject" 26 | initialProperties:nil 27 | launchOptions:launchOptions]; 28 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 29 | 30 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 31 | UIViewController *rootViewController = [UIViewController new]; 32 | rootViewController.view = rootView; 33 | self.window.rootViewController = rootViewController; 34 | [self.window makeKeyAndVisible]; 35 | return YES; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSTemporaryExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProject/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProjectTests/BundleUpdateProjectTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface BundleUpdateProjectTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation BundleUpdateProjectTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/ios/BundleUpdateProjectTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /testUpdateRn/BundleUpdateProject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BundleUpdateProject", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "15.2.1", 10 | "react-native": "^0.29.2" 11 | } 12 | } 13 | --------------------------------------------------------------------------------