├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .watchmanconfig ├── 01.jpg ├── 02.jpg ├── 03.gif ├── README.md ├── __tests__ ├── index.android.js └── index.ios.js ├── android.bundle ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Entypo.ttf │ │ │ ├── EvilIcons.ttf │ │ │ ├── FontAwesome.ttf │ │ │ ├── Foundation.ttf │ │ │ ├── Ionicons.ttf │ │ │ ├── MaterialCommunityIcons.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ ├── Octicons.ttf │ │ │ ├── SimpleLineIcons.ttf │ │ │ └── Zocial.ttf │ │ ├── java │ │ └── com │ │ │ └── learnproject │ │ │ ├── DetailActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ ├── SingleActivity.java │ │ │ ├── module │ │ │ └── DetailModule.java │ │ │ ├── rnpackage │ │ │ └── DetailPackage.java │ │ │ └── utils │ │ │ └── Contants.java │ │ └── res │ │ ├── layout │ │ └── activity_single_layout.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── 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 ├── rn-library │ ├── .gitignore │ ├── build.gradle │ ├── fat-aar.gradle │ ├── proguard-rules.pro │ ├── publish.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── shuyu │ │ │ └── rn │ │ │ └── SingleActivity.java │ │ └── res │ │ ├── layout │ │ └── activity_single_layout.xml │ │ └── values │ │ └── strings.xml └── settings.gradle ├── app.json ├── detail.js ├── home.js ├── index.android.js ├── index.ios.js ├── ios ├── learnProject-tvOS │ └── Info.plist ├── learnProject-tvOSTests │ └── Info.plist ├── learnProject.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── learnProject-tvOS.xcscheme │ │ └── learnProject.xcscheme ├── learnProject │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── learnProjectTests │ ├── Info.plist │ └── learnProjectTests.m ├── jscode ├── actions │ └── counter.js ├── common │ └── router.js ├── components │ ├── PhotoView.js │ ├── meteorListView.js │ ├── page2.js │ ├── tabListPage.js │ └── widget │ │ ├── button.js │ │ ├── counter.js │ │ ├── gridCount.js │ │ ├── listItem.js │ │ ├── recorder.js │ │ ├── slide.js │ │ └── tabIcon.js ├── img │ ├── loading.gif │ └── path │ │ └── LottieLogo1.json ├── reducers │ ├── counter.js │ └── index.js ├── store │ └── index.js └── style │ └── styles.js └── package.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | module.system=haste 26 | 27 | experimental.strict_type_args=true 28 | 29 | munge_underscores=true 30 | 31 | 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' 32 | 33 | suppress_type=$FlowIssue 34 | suppress_type=$FlowFixMe 35 | suppress_type=$FixMe 36 | 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-7]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-7]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 40 | 41 | unsafe.enable_getters_and_setters=true 42 | 43 | [version] 44 | ^0.37.0 45 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.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/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.apk 33 | 34 | # node.js 35 | # 36 | node_modules/ 37 | npm-debug.log 38 | yarn-error.log 39 | 40 | # BUCK 41 | buck-out/ 42 | \.buckd/ 43 | android/app/libs 44 | *.keystore 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/01.jpg -------------------------------------------------------------------------------- /02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/02.jpg -------------------------------------------------------------------------------- /03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/03.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 本项目是关于React Native相关的学习项目,不定时更新学习,欢迎交流讨论。 2 | 3 | ### **[**** 点击查看全新的完整学习项目 GSYGithubApp ****](https://github.com/CarGuo/GSYGithubAPP)** 4 | 5 | ### 说明 6 | 7 | 本项目后面会有相关的RN入门和项目介绍的文章,还有开发中的一些问题处理,第三方框架注意事项等,欢迎交流。 8 | 9 | **[1、从Android到React Native开发(一、入门)](http://www.jianshu.com/p/97692b1c451d)** 10 | 11 | **[2、从Android到React Native开发(二、通信与模块实现)](http://www.jianshu.com/p/bec040926db8)** 12 | 13 | **[3、从Android到React Native开发(三、自定义原生控件支持)](http://www.jianshu.com/p/a488674d55b3)** 14 | 15 | **[4、从Android到React Native开发(四、打包流程和发布为Maven库)](https://www.jianshu.com/p/f0aeaccc07a7)** 16 | 17 | 18 | ![公众号](http://img.cdn.guoshuyu.cn/WeChat-Code) 19 | 20 | --------------------------------------------- 21 | 22 | ### 为什么要有这个项目 23 | 作为一个原生开发者,从不懂JS,ES6,react,redux等,如何快速的了解和使用React Native,也许这里可以帮助到你。 24 | 25 | 项目主要是对于RN的控件,第三方控件,框架的使用和推荐,希望可以帮助那些原生APP开发的猿们更好的了解RN的世界。 26 | 27 | 项目会不定时的更新,根据个人对第三方框架的使用,和RN相关的学习,会持续更新项目和完善文档。 28 | 29 | ### 为什么要学习React Native 30 | 31 | 这可能是很多原生App开发者的问题,个人觉得,学习RN可以是对原生的一种补充,也是接触学习js的一种契机,作为程序员危机感的自我提升等等,最重要的是个人兴趣和项目需要吧!js其实是一种特别的魅力。 32 | 33 | ### 目前使用的相关框架: 34 | 35 | * [react-native-router-flux](https://github.com/aksonov/react-native-router-flux) 36 | * [react-native-swipe-list-view](https://github.com/jemise111/react-native-swipe-list-view) 37 | * [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) 38 | * [redux-thunk](https://github.com/gaearon/redux-thunk) 39 | * [react-native-modalbox](https://github.com/maxs15/react-native-modalbox) 40 | * [react-native-spinkit](https://github.com/maxs15/react-native-spinkit) 41 | * [lottie-react-native](https://github.com/airbnb/lottie-react-native) 42 | * [react-native-audio](https://github.com/CarGuo/react-native-audio) 43 | * [react-native-easy-grid](https://github.com/GeekyAnts/react-native-easy-grid) 44 | * [react-native-autolink](https://github.com/joshswan/react-native-autolink) 45 | 46 | 47 | * 与原生Activity双向交互。(仅Android) 48 | * 动态加载下载的js显示运行。(仅Android) 49 | * 动态打包react native项目为aar。(仅Android) 50 | 51 | 52 | ![](https://ooo.0o0.ooo/2017/06/18/5946390d5671a.gif) 53 | ![](https://ooo.0o0.ooo/2017/06/18/5946390b83620.jpg) 54 | ![](https://ooo.0o0.ooo/2017/06/18/5946390d7db3b.jpg) 55 | -------------------------------------------------------------------------------- /__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /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.learnproject', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.learnproject', 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 | -------------------------------------------------------------------------------- /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.learnproject" 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-audio') 130 | compile project(':lottie-react-native') 131 | compile project(':react-native-spinkit') 132 | compile project(':react-native-vector-icons') 133 | compile project(':react-native-photo-view') 134 | compile fileTree(dir: "libs", include: ["*.jar"]) 135 | compile "com.android.support:appcompat-v7:23.0.1" 136 | compile "com.facebook.react:react-native:+" // From node_modules 137 | // 如果你需要支持GIF动图 138 | compile 'com.facebook.fresco:animated-gif:0.11.0' 139 | compile 'com.facebook.fresco:fresco:0.11.0' 140 | compile 'cn.finalteam:okhttpfinal:2.0.7' 141 | compile 'com.github.ForgetAll:LoadingDialog:v1.0.4' 142 | } 143 | 144 | // Run this once to be able to run the application with BUCK 145 | // puts all compile dependencies into folder libs for BUCK to use 146 | task copyDownloadableDepsToLibs(type: Copy) { 147 | from configurations.compile 148 | into 'libs' 149 | } 150 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.learnproject; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | import android.widget.Toast; 9 | 10 | import com.facebook.react.ReactActivity; 11 | import com.facebook.react.ReactPackage; 12 | import com.facebook.react.shell.MainReactPackage; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | import java.util.concurrent.ArrayBlockingQueue; 17 | 18 | /** 19 | * Created by shuyu on 2017/2/20. 20 | * 新的activity用于承载新的react页面 21 | */ 22 | public class DetailActivity extends ReactActivity { 23 | 24 | private static int i = 0; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | i++; 30 | Log.e("DetailActivity " , "DetailActivity onCreate "); 31 | } 32 | 33 | @Override 34 | public void onNewIntent(Intent intent) { 35 | super.onNewIntent(intent); 36 | 37 | Log.e("DetailActivity " , "DetailActivity Intent "); 38 | overridePendingTransition(R.anim.fade_in, R.anim.fade_out); 39 | } 40 | 41 | @Override 42 | protected void onDestroy() { 43 | super.onDestroy(); 44 | Log.e("DetailActivity " , "DetailActivity onDestroy "); 45 | } 46 | 47 | /** 48 | * Returns the name of the main component registered from JavaScript. 49 | * This is used to schedule rendering of the component. 50 | *

51 | * 这里指定了js的默认加载类名字,然后你需要在js中register它 52 | */ 53 | @Override 54 | protected String getMainComponentName() { 55 | return "detail"; 56 | } 57 | 58 | @Override 59 | public void onBackPressed() { 60 | Intent intent = new Intent(); 61 | //intent.putExtra("result", "我是传说中的返回数据 " + i--); 62 | //setResult(Activity.RESULT_OK, intent); 63 | 64 | //super.onBackPressed(); 65 | intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 66 | intent.setClass(this, MainActivity.class); 67 | startActivity(intent); 68 | } 69 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.learnproject; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.widget.Toast; 8 | 9 | import com.facebook.react.ReactActivity; 10 | import com.oblador.vectoricons.VectorIconsPackage; 11 | 12 | import java.util.concurrent.ArrayBlockingQueue; 13 | 14 | public class MainActivity extends ReactActivity { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | 20 | Log.e("MainActivity " , "MainActivity onCreate "); 21 | } 22 | 23 | @Override 24 | public void onNewIntent(Intent intent) { 25 | super.onNewIntent(intent); 26 | 27 | Log.e("MainActivity " , "MainActivity Intent "); 28 | overridePendingTransition(R.anim.fade_in, R.anim.fade_out); 29 | } 30 | 31 | @Override 32 | protected void onDestroy() { 33 | super.onDestroy(); 34 | Log.e("MainActivity " , "MainActivity onDestroy "); 35 | } 36 | 37 | /** 38 | * Returns the name of the main component registered from JavaScript. 39 | * This is used to schedule rendering of the component. 40 | */ 41 | @Override 42 | protected String getMainComponentName() { 43 | return "learnProject"; 44 | } 45 | 46 | 47 | 48 | @Override 49 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 50 | super.onActivityResult(requestCode, resultCode, data); 51 | 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.learnproject; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.rnim.rn.audio.ReactNativeAudioPackage; 8 | import com.airbnb.android.react.lottie.LottiePackage; 9 | import com.react.rnspinkit.RNSpinkitPackage; 10 | import com.reactnative.photoview.PhotoViewPackage; 11 | import com.facebook.react.ReactInstanceManager; 12 | import com.facebook.react.ReactNativeHost; 13 | import com.facebook.react.ReactPackage; 14 | import com.facebook.react.shell.MainReactPackage; 15 | import com.facebook.soloader.SoLoader; 16 | import com.oblador.vectoricons.VectorIconsPackage; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | import com.learnproject.rnpackage.DetailPackage; 22 | import com.xiasuhuei321.loadingdialog.manager.StyleManager; 23 | import com.xiasuhuei321.loadingdialog.view.LoadingDialog; 24 | 25 | import cn.finalteam.okhttpfinal.OkHttpFinal; 26 | import cn.finalteam.okhttpfinal.OkHttpFinalConfiguration; 27 | 28 | public class MainApplication extends Application implements ReactApplication { 29 | 30 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 31 | @Override 32 | public boolean getUseDeveloperSupport() { 33 | return BuildConfig.DEBUG; 34 | } 35 | 36 | @Override 37 | protected List getPackages() { 38 | return Arrays.asList( 39 | new MainReactPackage(), 40 | new ReactNativeAudioPackage(), 41 | new LottiePackage(), 42 | new RNSpinkitPackage(), 43 | new PhotoViewPackage(), 44 | new VectorIconsPackage(), 45 | new DetailPackage() 46 | ); 47 | } 48 | }; 49 | 50 | @Override 51 | public ReactNativeHost getReactNativeHost() { 52 | return mReactNativeHost; 53 | } 54 | 55 | @Override 56 | public void onCreate() { 57 | super.onCreate(); 58 | SoLoader.init(this, /* native exopackage */ false); 59 | OkHttpFinalConfiguration.Builder builder = new OkHttpFinalConfiguration.Builder(); 60 | OkHttpFinal.getInstance().init(builder.build()); 61 | 62 | StyleManager styleManager = new StyleManager(); 63 | styleManager.Anim(false).repeatTime(0).contentSize(-1).intercept(true); 64 | LoadingDialog.initStyle(styleManager); 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/SingleActivity.java: -------------------------------------------------------------------------------- 1 | package com.learnproject; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.os.Environment; 6 | import android.view.KeyEvent; 7 | import android.widget.Toast; 8 | 9 | import com.airbnb.android.react.lottie.LottiePackage; 10 | import com.facebook.react.ReactInstanceManager; 11 | import com.facebook.react.ReactRootView; 12 | import com.facebook.react.bridge.NativeModuleCallExceptionHandler; 13 | import com.facebook.react.common.LifecycleState; 14 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 15 | import com.facebook.react.shell.MainReactPackage; 16 | import com.learnproject.rnpackage.DetailPackage; 17 | import com.learnproject.utils.Contants; 18 | import com.reactnative.photoview.PhotoViewPackage; 19 | import com.xiasuhuei321.loadingdialog.view.LoadingDialog; 20 | 21 | import java.io.File; 22 | 23 | import cn.finalteam.okhttpfinal.FileDownloadCallback; 24 | import cn.finalteam.okhttpfinal.HttpRequest; 25 | 26 | /** 27 | * Created by guoshuyu on 2017/2/22. 28 | * 29 | * 主要测试的加载远程js bundle 到本地 30 | * 31 | * 需要注意是否支持原生代码在已经在Main那里注册了,这里是否支持用package使用。 32 | * 需要注意命名空间是否会重复问题。 33 | */ 34 | 35 | public class SingleActivity extends Activity implements DefaultHardwareBackBtnHandler { 36 | 37 | ReactRootView mReactRootView; 38 | 39 | ReactInstanceManager mReactInstanceManager; 40 | 41 | LoadingDialog mLoadingDialog; 42 | 43 | //todo 记得把项目根目录下的 android.bundle 放到手机的根目录下。因为网络url估计失效了 44 | String path = Environment.getExternalStorageDirectory().getPath() + "/android.bundle"; 45 | 46 | @Override 47 | protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | 50 | setContentView(R.layout.activity_single_layout); 51 | 52 | mReactRootView = (ReactRootView) findViewById(R.id.single_react_root_view); 53 | 54 | if (new File(path).exists()) { 55 | setReactNative(); 56 | } else { 57 | 58 | mLoadingDialog = new LoadingDialog(this); 59 | mLoadingDialog.setLoadingText("加载中..."); 60 | mLoadingDialog.show(); 61 | 62 | downLoadBundle(Contants.URL, path); 63 | } 64 | } 65 | 66 | @Override 67 | public void invokeDefaultOnBackPressed() { 68 | super.onBackPressed(); 69 | } 70 | 71 | @Override 72 | protected void onPause() { 73 | super.onPause(); 74 | 75 | if (mReactInstanceManager != null) { 76 | mReactInstanceManager.onHostPause(this); 77 | } 78 | } 79 | 80 | @Override 81 | protected void onResume() { 82 | super.onResume(); 83 | 84 | if (mReactInstanceManager != null) { 85 | mReactInstanceManager.onHostResume(this, this); 86 | } 87 | } 88 | 89 | 90 | @Override 91 | protected void onDestroy() { 92 | super.onDestroy(); 93 | 94 | if (mReactInstanceManager != null) { 95 | mReactInstanceManager.onHostDestroy(this); 96 | } 97 | } 98 | 99 | 100 | @Override 101 | public void onBackPressed() { 102 | if (mReactInstanceManager != null) { 103 | mReactInstanceManager.onBackPressed(); 104 | } else { 105 | super.onBackPressed(); 106 | } 107 | } 108 | 109 | @Override 110 | public boolean onKeyUp(int keyCode, KeyEvent event) { 111 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 112 | mReactInstanceManager.showDevOptionsDialog(); 113 | return true; 114 | } 115 | return super.onKeyUp(keyCode, event); 116 | } 117 | 118 | 119 | private void downLoadBundle(String url, String path) { 120 | 121 | File saveFile = new File(path); 122 | HttpRequest.download(url, saveFile, new FileDownloadCallback() { 123 | //开始下载 124 | @Override 125 | public void onStart() { 126 | super.onStart(); 127 | } 128 | 129 | //下载进度 130 | @Override 131 | public void onProgress(int progress, long networkSpeed) { 132 | super.onProgress(progress, networkSpeed); 133 | } 134 | 135 | //下载失败 136 | @Override 137 | public void onFailure() { 138 | super.onFailure(); 139 | Toast.makeText(getBaseContext(), "下载失败", Toast.LENGTH_SHORT).show(); 140 | mLoadingDialog.loadFailed(); 141 | } 142 | 143 | //下载完成(下载成功) 144 | @Override 145 | public void onDone() { 146 | super.onDone(); 147 | Toast.makeText(getBaseContext(), "下载成功", Toast.LENGTH_SHORT).show(); 148 | mLoadingDialog.loadSuccess(); 149 | setReactNative(); 150 | } 151 | }); 152 | } 153 | 154 | 155 | 156 | private void setReactNative() { 157 | if (new File(path).exists()) { 158 | mReactInstanceManager = ReactInstanceManager.builder() 159 | .setApplication(this.getApplication()) 160 | .setJSBundleFile(path)//设置加载文件 161 | .setNativeModuleCallExceptionHandler(new NativeModuleCallExceptionHandler() { 162 | @Override 163 | public void handleException(Exception e) { 164 | e.printStackTrace(); 165 | } 166 | }) 167 | .addPackage(new DetailPackage()) 168 | .addPackage(new MainReactPackage()) 169 | .addPackage(new LottiePackage()) 170 | .addPackage(new PhotoViewPackage()) 171 | .setJSMainModuleName("learnProject")// 172 | .setUseDeveloperSupport(false) 173 | .setInitialLifecycleState(LifecycleState.RESUMED) 174 | .build(); 175 | mReactRootView.startReactApplication(mReactInstanceManager, "learnProject", null);//启动入口 176 | } else { 177 | Toast.makeText(this, "请把项目根目录下的 android.bundle 放到手机的根目录下。", Toast.LENGTH_LONG).show(); 178 | } 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/module/DetailModule.java: -------------------------------------------------------------------------------- 1 | 2 | package com.learnproject.module; 3 | 4 | import com.facebook.react.bridge.ActivityEventListener; 5 | import com.facebook.react.bridge.Arguments; 6 | import com.facebook.react.bridge.Callback; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContext; 9 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 10 | import com.facebook.react.bridge.ReactMethod; 11 | 12 | import android.app.Activity; 13 | import android.content.Intent; 14 | import android.support.annotation.Nullable; 15 | import android.text.TextUtils; 16 | 17 | import com.facebook.react.bridge.WritableMap; 18 | import com.facebook.react.modules.core.DeviceEventManagerModule; 19 | import com.learnproject.DetailActivity; 20 | import com.learnproject.MainActivity; 21 | import com.learnproject.R; 22 | import com.learnproject.SingleActivity; 23 | 24 | import java.util.ArrayList; 25 | import java.util.HashMap; 26 | import java.util.List; 27 | 28 | 29 | /** 30 | * 定一个module,用于在RN中可以方便传递和调用 31 | */ 32 | public class DetailModule extends ReactContextBaseJavaModule implements ActivityEventListener { 33 | 34 | private final ReactApplicationContext reactContext; 35 | 36 | //保存打开的activity,js里的回调接口 37 | private List successCallBack = new ArrayList<>(); 38 | 39 | public DetailModule(ReactApplicationContext reactContext) { 40 | super(reactContext); 41 | this.reactContext = reactContext; 42 | //注册activity的打开和返回监听,用于activity返回的时候回调 43 | reactContext.addActivityEventListener(this); 44 | } 45 | 46 | //定义一个module名字 47 | @Override 48 | public String getName() { 49 | return "DetailModule"; 50 | } 51 | 52 | //定义一个方法,让js可以收到参数 53 | @ReactMethod 54 | public void getDataFromIntent(Callback successBack, Callback erroBack) { 55 | try { 56 | Activity currentActivity = getCurrentActivity(); 57 | String result_text1 = currentActivity.getIntent().getStringExtra("result_text1");//会有对应数据放入 58 | String result_text2 = currentActivity.getIntent().getStringExtra("result_text2");//会有对应数据放入 59 | String result_text3 = currentActivity.getIntent().getStringExtra("result_text3");//会有对应数据放入 60 | String result_text4 = currentActivity.getIntent().getStringExtra("result_text4");//会有对应数据放入 61 | if (TextUtils.isEmpty(result_text1)) { 62 | result_text1 = "No Data"; 63 | } 64 | if (TextUtils.isEmpty(result_text2)) { 65 | result_text2 = "No Data"; 66 | } 67 | if (TextUtils.isEmpty(result_text3)) { 68 | result_text3 = "No Data"; 69 | } 70 | if (TextUtils.isEmpty(result_text4)) { 71 | result_text4 = "No Data"; 72 | } 73 | successBack.invoke(result_text1, result_text2, result_text3, result_text4); 74 | } catch (Exception e) { 75 | erroBack.invoke(e.getMessage()); 76 | } 77 | } 78 | 79 | 80 | //定义一个react native 调用的方法 81 | @ReactMethod 82 | public void startActivityByRN(final String text1, final String text2, final String text3, final String text4, 83 | final Callback successBack, final Callback errorBack) { 84 | successCallBack.add(successBack); 85 | try { 86 | Activity currentActivity = getCurrentActivity(); 87 | if (null != currentActivity) { 88 | Intent intent = new Intent(currentActivity, DetailActivity.class); 89 | intent.putExtra("result_text1", text1); 90 | intent.putExtra("result_text2", text2); 91 | intent.putExtra("result_text3", text3); 92 | intent.putExtra("result_text4", text4); 93 | intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 94 | //currentActivity.startActivityForResult(intent, 1100); 95 | currentActivity.startActivity(intent); 96 | } 97 | } catch (Exception e) { 98 | e.printStackTrace(); 99 | errorBack.invoke(e.getMessage()); 100 | } 101 | 102 | } 103 | 104 | //定义一个react native 调用的方法 105 | @ReactMethod 106 | public void startActivitySingle(final Callback successBack, final Callback errorBack) { 107 | successCallBack.add(successBack); 108 | try { 109 | Activity currentActivity = getCurrentActivity(); 110 | if (null != currentActivity) { 111 | Intent intent = new Intent(currentActivity, SingleActivity.class); 112 | currentActivity.startActivity(intent); 113 | } 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | errorBack.invoke(e.getMessage()); 117 | } 118 | 119 | } 120 | 121 | @Override 122 | public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { 123 | 124 | if (resultCode == Activity.RESULT_OK && requestCode == 1100) { 125 | if (data != null) { 126 | String result = data.getStringExtra("result"); 127 | if (!TextUtils.isEmpty(result)) { 128 | callLogic(result); 129 | } else { 130 | callLogic("无数据传回"); 131 | } 132 | } else { 133 | callLogic("无数据传回"); 134 | } 135 | 136 | WritableMap params = Arguments.createMap(); 137 | HashMap hashMap = new HashMap<>(); 138 | params.putString("result", "我是通过Detail消息推送过来的!"); 139 | sendEvent(reactContext, "backFromDetail", params); 140 | } 141 | } 142 | 143 | @Override 144 | public void onNewIntent(Intent intent) { 145 | 146 | } 147 | 148 | private void sendEvent(ReactContext reactContext, 149 | String eventName, 150 | @Nullable WritableMap params) { 151 | reactContext 152 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 153 | .emit(eventName, params); 154 | } 155 | 156 | //输出回调 157 | private void callLogic(String string) { 158 | if (successCallBack.size() > 0) { 159 | successCallBack.get(successCallBack.size() - 1).invoke(string); 160 | successCallBack.remove(successCallBack.size() - 1); 161 | } 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/rnpackage/DetailPackage.java: -------------------------------------------------------------------------------- 1 | package com.learnproject.rnpackage; 2 | 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | 14 | import com.learnproject.module.DetailModule; 15 | 16 | /** 17 | * ReactPackage 用于关联,并且在Application注册 18 | * */ 19 | public class DetailPackage implements ReactPackage { 20 | @Override 21 | public List createNativeModules(ReactApplicationContext reactContext) { 22 | return Arrays.asList(new DetailModule(reactContext)); 23 | } 24 | 25 | @Override 26 | public List> createJSModules() { 27 | return Collections.emptyList(); 28 | } 29 | 30 | @Override 31 | public List createViewManagers(ReactApplicationContext reactContext) { 32 | return Collections.emptyList(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/learnproject/utils/Contants.java: -------------------------------------------------------------------------------- 1 | package com.learnproject.utils; 2 | 3 | /** 4 | * Created by guoshuyu on 2017/2/22. 5 | */ 6 | 7 | public class Contants { 8 | public static final String URL = "https://nj01ct01.baidupcs.com/file/2871eceafc7a1af2b3a245eec8f42289?bkt=p3-14002871eceafc7a1af2b3a245eec8f42289f2efb48a0000000c8bac&fid=4245627009-250528-940777342279401&time=1487753991&sign=FDTAXGERLBHS-DCb740ccc5511e5e8fedcff06b081203-yXVB6NDRUpAro1f6udVxTpUwIXs%3D&to=63&size=822188&sta_dx=822188&sta_cs=0&sta_ft=bundle&sta_ct=0&sta_mt=0&fm2=MH,Yangquan,Netizen-anywhere,,guangdongct&newver=1&newfm=1&secfm=1&flow_ver=3&pkey=14002871eceafc7a1af2b3a245eec8f42289f2efb48a0000000c8bac&sl=72286287&expires=8h&rt=sh&r=852582362&mlogid=1222452881945777155&vuk=4245627009&vbdid=2659063173&fin=android.bundle&fn=android.bundle&rtype=1&iv=0&dp-logid=1222452881945777155&dp-callid=0.1.1&hps=1&csl=400&csign=aq2MmSgNh%2BgNx7WEpm3bYZfXVF8%3D&by=themis"; 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_single_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | learnProject 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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.2.2' 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 | // Add jitpack repository (added by react-native-spinkit) 18 | maven { 19 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 20 | url "$rootDir/../node_modules/react-native/android" 21 | } 22 | maven { url "https://jitpack.io" } 23 | mavenLocal() 24 | jcenter() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/LearnProject/41c694e7f3f4a74a85a9aff4a2b896a96c61df86/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /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.14.1-all.zip 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/rn-library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/rn-library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | group "com.shuyu.rn" 4 | 5 | version '1.0.0' 6 | 7 | 8 | project.ext.react = [ 9 | jsBundleDirRelease : "$buildDir/intermediates/bundles/release/assets", 10 | resourcesDirRelease: "$buildDir/intermediates/bundles/release/res", 11 | ] 12 | 13 | //引入react脚本 14 | apply from: "../../node_modules/react-native/react.gradle" 15 | apply from: "fat-aar.gradle" 16 | 17 | android { 18 | 19 | compileSdkVersion 23 20 | 21 | buildToolsVersion "23.0.1" 22 | 23 | defaultConfig { 24 | minSdkVersion 19 25 | targetSdkVersion 23 26 | versionCode 1 27 | versionName "1.0" 28 | 29 | } 30 | 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | 38 | lintOptions { 39 | abortOnError false 40 | } 41 | 42 | } 43 | 44 | dependencies { 45 | compile fileTree(dir: 'libs', include: ['*.jar']) 46 | compile "com.android.support:appcompat-v7:23.0.1" 47 | 48 | embedded project(':react-native-audio') 49 | embedded project(':lottie-react-native') 50 | embedded project(':react-native-spinkit') 51 | embedded project(':react-native-vector-icons') 52 | embedded project(':react-native-photo-view') 53 | compile fileTree(dir: "libs", include: ["*.jar"]) 54 | 55 | embedded "com.facebook.react:react-native:+" // From node_modules 56 | // 如果你需要支持GIF动图 57 | embedded 'com.facebook.fresco:animated-gif:0.11.0' 58 | } 59 | 60 | apply from: "publish.gradle" -------------------------------------------------------------------------------- /android/rn-library/fat-aar.gradle: -------------------------------------------------------------------------------- 1 | import com.android.annotations.NonNull 2 | 3 | import com.android.manifmerger.ManifestMerger2 4 | 5 | import com.android.manifmerger.ManifestMerger2.Invoker 6 | 7 | import com.android.manifmerger.ManifestMerger2.MergeType 8 | 9 | import com.android.manifmerger.MergingReport 10 | 11 | import com.android.manifmerger.PlaceholderEncoder 12 | 13 | import com.android.manifmerger.XmlDocument 14 | 15 | import com.android.utils.ILogger 16 | 17 | import com.google.common.base.Charsets 18 | 19 | import com.google.common.io.Files 20 | 21 | import org.gradle.util.GradleVersion 22 | 23 | 24 | 25 | buildscript { 26 | 27 | repositories { 28 | 29 | jcenter() 30 | 31 | } 32 | 33 | 34 | 35 | dependencies { 36 | 37 | classpath 'com.android.tools.build:manifest-merger:25.3.3' 38 | 39 | } 40 | 41 | } 42 | 43 | //这里是定义了一个configuration,而这个configurations 映射的则是一个 ConfigurationContainer对象 44 | //Configuration对象包含有 dependencies 、 artifacts 属性 45 | configurations { 46 | // embedded 实际上是一个 configuration 47 | // embedded project(':module') 48 | // 则是将这个 project 作为 dependency add 进了这个 configuration ,同时返回这个Dependency对象。 49 | embedded 50 | 51 | } 52 | 53 | //embedded是自定义的一种configuration, 然后通过dependencies把embedded配置的依赖 compile进来 54 | dependencies { 55 | 56 | compile configurations.embedded 57 | 58 | } 59 | 60 | 61 | 62 | ext { 63 | 64 | gradleVersionStr = GradleVersion.current().getVersion() 65 | 66 | gradleApiVersion = gradleVersionStr.substring(0, gradleVersionStr.lastIndexOf(".")).toFloat() 67 | 68 | println "Current Gradle Version: $gradleVersionStr" 69 | 70 | 71 | 72 | // Paths to embedded jar files 73 | 74 | embeddedJars = new ArrayList() 75 | 76 | // Paths to embedded aar projects 77 | 78 | embeddedAarDirs = new ArrayList() 79 | 80 | // Embedded aar files dependencies 81 | 82 | embeddedAarFiles = new ArrayList() 83 | 84 | // List of embedded R classes 85 | 86 | embeddedRClasses = new ArrayList() 87 | 88 | // Jar file name for embedded R classes 89 | 90 | archiveNameOfRClasses = "embeddedRClasses.jar" 91 | 92 | 93 | 94 | // Change backslash to forward slash on windows 95 | 96 | build_dir = buildDir.path.replace(File.separator, '/') 97 | 98 | root_dir = project.rootDir.absolutePath.replace(File.separator, '/') 99 | 100 | exploded_aar_dir = "$build_dir/intermediates/exploded-aar" 101 | 102 | classs_release_dir = "$build_dir/intermediates/classes/release" 103 | 104 | //bundle_release_dir = "$build_dir/intermediates/bundles/default" 105 | bundle_release_dir = "$build_dir/intermediates/bundles/release" 106 | 107 | manifest_aapt_dir = "$build_dir/intermediates/manifests/aapt/release" 108 | 109 | generated_rsrc_dir = "$build_dir/generated/source/r/release" 110 | 111 | bundle_libs_dir = "$bundle_release_dir/libs" 112 | 113 | bundle_jni_dir = "$bundle_release_dir/jni" 114 | 115 | 116 | 117 | base_fataar_dir = "$build_dir/fat-aar" 118 | 119 | new_r_class_dir = "$base_fataar_dir/RClass" 120 | 121 | extra_jar_dir = "$base_fataar_dir/libs" 122 | 123 | } 124 | 125 | 126 | 127 | afterEvaluate { 128 | 129 | // 定义一个包含 Dependencies 的list 130 | // the list of dependency must be reversed to use the right overlay order. 131 | def dependencies = new ArrayList(configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies) 132 | 133 | println "Total Modules:" + dependencies.size() 134 | 135 | //遍历依赖将确定的路径放到另一个list embeddedAarDirs 中。 136 | dependencies.reverseEach { 137 | 138 | def aarPath 139 | 140 | if (gradleApiVersion >= 2.3f) { 141 | 142 | aarPath = "${root_dir}/${it.moduleName}/build/intermediates/bundles/default" 143 | 144 | } else { 145 | 146 | aarPath = "${exploded_aar_dir}/${it.moduleGroup}/${it.moduleName}/${it.moduleVersion}" 147 | 148 | } 149 | 150 | 151 | 152 | it.moduleArtifacts.each { artifact -> 153 | 154 | println "Module File: $artifact" 155 | 156 | if (artifact.type == 'aar') { 157 | 158 | if (!embeddedAarFiles.contains(artifact)) { 159 | 160 | embeddedAarFiles.add(artifact) 161 | 162 | } 163 | 164 | 165 | 166 | if (!embeddedAarDirs.contains(aarPath)) { 167 | 168 | embeddedAarDirs.add(aarPath) 169 | 170 | } 171 | 172 | } else if (artifact.type == 'jar') { 173 | 174 | if (!embeddedJars.contains(artifact.file)) { 175 | 176 | embeddedJars.add(artifact.file) 177 | 178 | } 179 | 180 | } else { 181 | 182 | println "Unsupported Type: ${artifact.type}" 183 | 184 | throw new Exception("Unsupported Type: ${artifact.type}") 185 | 186 | } 187 | 188 | } 189 | 190 | } 191 | 192 | //通过不同的task之间的dependsOn ,mustRunAfter 这种方式来插入自定义的task 193 | if (dependencies.size() > 0) { 194 | 195 | // Merge Assets 196 | 197 | generateReleaseAssets.dependsOn embedAssets 198 | 199 | embedAssets.dependsOn prepareReleaseDependencies 200 | 201 | 202 | 203 | // Embed Resources by overwriting the inputResourceSets 204 | 205 | packageReleaseResources.dependsOn embedLibraryResources 206 | 207 | embedLibraryResources.dependsOn prepareReleaseDependencies 208 | 209 | 210 | 211 | // Embed JNI Libraries 212 | 213 | bundleRelease.dependsOn embedJniLibs 214 | 215 | 216 | 217 | if (gradleApiVersion >= 2.3f) { 218 | 219 | embedJniLibs.dependsOn transformNativeLibsWithSyncJniLibsForRelease 220 | 221 | ext.bundle_release_dir = "$build_dir/intermediates/bundles/default" 222 | 223 | } else { 224 | 225 | embedJniLibs.dependsOn transformNative_libsWithSyncJniLibsForRelease 226 | 227 | ext.bundle_release_dir = "$build_dir/intermediates/bundles/release" 228 | 229 | } 230 | 231 | 232 | 233 | // Merge Embedded Manifests 234 | 235 | bundleRelease.dependsOn embedManifests 236 | 237 | embedManifests.dependsOn processReleaseManifest 238 | 239 | 240 | 241 | // Merge proguard files 242 | 243 | embedLibraryResources.dependsOn embedProguard 244 | 245 | embedProguard.dependsOn prepareReleaseDependencies 246 | 247 | 248 | 249 | // Generate R.java files 250 | 251 | compileReleaseJavaWithJavac.dependsOn generateRJava 252 | 253 | generateRJava.dependsOn processReleaseResources 254 | 255 | 256 | 257 | // Bundle the java classes 258 | 259 | bundleRelease.dependsOn embedJavaJars 260 | 261 | embedJavaJars.dependsOn compileReleaseJavaWithJavac 262 | 263 | 264 | 265 | // Copy extra jars to bundle release libs directory 266 | 267 | bundleRelease.dependsOn copyEmbedJars 268 | 269 | copyEmbedJars.dependsOn transformClassesAndResourcesWithSyncLibJarsForRelease 270 | 271 | 272 | 273 | // If proguard is enabled, run the tasks that bundleRelease should depend on before proguard 274 | 275 | if (tasks.findByPath('proguardRelease') != null) { 276 | 277 | proguardRelease.dependsOn embedJavaJars 278 | 279 | } else if (tasks.findByPath('transformClassesAndResourcesWithProguardForRelease') != null) { 280 | 281 | transformClassesAndResourcesWithProguardForRelease.dependsOn embedJavaJars 282 | 283 | } 284 | 285 | } 286 | 287 | } 288 | 289 | 290 | 291 | task embedLibraryResources { 292 | 293 | doLast { 294 | 295 | def oldInputResourceSet = packageReleaseResources.inputResourceSets 296 | 297 | packageReleaseResources.conventionMapping.map("inputResourceSets") { 298 | 299 | getMergedInputResourceSets(oldInputResourceSet) 300 | 301 | } 302 | 303 | } 304 | 305 | } 306 | 307 | 308 | 309 | private List getMergedInputResourceSets(List inputResourceSet) { 310 | 311 | println "call getMergedInputResourceSets" 312 | 313 | 314 | 315 | //We need to do this trickery here since the class declared here and that used by the runtime 316 | 317 | //are different and results in class cast error 318 | 319 | def ResourceSetClass = inputResourceSet.get(0).class 320 | 321 | List newInputResourceSet = new ArrayList(inputResourceSet) 322 | 323 | 324 | 325 | embeddedAarDirs.each { aarPath -> 326 | 327 | try { 328 | 329 | def resname 330 | 331 | if (gradleApiVersion >= 2.3f) { 332 | 333 | def parentProject = project.rootProject.name.toString() 334 | 335 | 336 | 337 | def startIndex = aarPath.indexOf('/' + parentProject) 338 | 339 | def endIndex = aarPath.indexOf('/build/') 340 | 341 | 342 | 343 | if (startIndex < 1 || endIndex < 1) { 344 | 345 | println "Module error:$aarPath, other info: startIndex = $startIndex, endIndex = $endIndex" 346 | 347 | return 348 | 349 | } 350 | 351 | 352 | 353 | resname = aarPath.substring(startIndex, endIndex).replace('/', ':') 354 | 355 | } else { 356 | 357 | resname = (aarPath.split(exploded_aar_dir)[1]).replace('/', ':') 358 | 359 | } 360 | 361 | 362 | 363 | def rs = ResourceSetClass.newInstance([resname, true] as Object[]) 364 | 365 | rs.addSource(file("$aarPath/res")) 366 | 367 | newInputResourceSet += rs 368 | 369 | 370 | 371 | println "====Merged resource: $rs." 372 | 373 | } catch (Exception e) { 374 | 375 | e.printStackTrace() 376 | 377 | throw e 378 | 379 | } 380 | 381 | } 382 | 383 | 384 | 385 | return newInputResourceSet 386 | 387 | } 388 | 389 | 390 | 391 | /** 392 | * Assets are simple files, so just adding them to source set seems to work. 393 | */ 394 | 395 | task embedAssets { 396 | 397 | doLast { 398 | 399 | embeddedAarDirs.each { aarPath -> 400 | 401 | // Merge Assets 402 | 403 | println "====Merged: $aarPath/assets" 404 | 405 | android.sourceSets.main.assets.srcDirs += file("$aarPath/assets") 406 | 407 | } 408 | 409 | } 410 | 411 | } 412 | 413 | 414 | 415 | /** 416 | * Merge proguard.txt files from all library modules 417 | * @author Marian Klühspies 418 | */ 419 | 420 | task embedProguard { 421 | 422 | doLast { 423 | 424 | def proguardRelease = file("$bundle_release_dir/proguard.txt") 425 | 426 | if (proguardRelease.exists()) { 427 | 428 | proguardRelease.delete() 429 | 430 | proguardRelease.createNewFile() 431 | 432 | } 433 | 434 | 435 | 436 | embeddedAarDirs.each { aarPath -> 437 | 438 | try { 439 | 440 | println "====Merged: $aarPath/proguard.txt" 441 | 442 | 443 | 444 | def proguardLibFile = file("$aarPath/proguard.txt") 445 | 446 | if (proguardLibFile.exists()) { 447 | 448 | proguardRelease.append(proguardLibFile.text) 449 | 450 | proguardRelease.append("\n") 451 | 452 | } 453 | 454 | } catch (Exception e) { 455 | 456 | e.printStackTrace() 457 | 458 | throw e 459 | 460 | } 461 | 462 | } 463 | 464 | 465 | 466 | println "====Final Merged: $proguardRelease" 467 | 468 | } 469 | 470 | } 471 | 472 | 473 | 474 | task generateRJava { 475 | 476 | doLast { 477 | 478 | // Now generate the R.java file for each embedded dependency 479 | 480 | def export_package_name = "com.pax.exportaar" 481 | 482 | def mainManifestFile = android.sourceSets.main.manifest.srcFile 483 | 484 | if (mainManifestFile.exists()) { 485 | 486 | export_package_name = new XmlParser().parse(mainManifestFile).@package 487 | 488 | } 489 | 490 | 491 | def rClassFile = file("$generated_rsrc_dir/com/shuyu/rn/R.java") 492 | def rClassMap = new ConfigObject() 493 | 494 | def subClassName = null 495 | 496 | if (rClassFile.exists()) { 497 | rClassFile.eachLine { 498 | line -> 499 | line = line.trim() 500 | if(line.contains("public static final class ")) { 501 | def subline = line.substring(("public static final class ").length()) 502 | subClassName = subline.substring(0, subline.indexOf(" ")) 503 | } else if (line.contains("public static int ")) { 504 | def subline = line.substring(("public static int ").length()) 505 | def name = subline.substring(0, subline.indexOf("=")) 506 | rClassMap[subClassName].putAt(name, 1) 507 | } 508 | } 509 | } 510 | 511 | 512 | embeddedAarDirs.each { aarPath -> 513 | 514 | def manifestFile = file("$aarPath/AndroidManifest.xml") 515 | 516 | if (!manifestFile.exists()) { 517 | 518 | manifestFile = file("./src/main/AndroidManifest.xml") 519 | 520 | } 521 | 522 | 523 | 524 | if (manifestFile.exists()) { 525 | 526 | def aarManifest = new XmlParser().parse(manifestFile) 527 | 528 | def aarPackageName = aarManifest.@package 529 | 530 | 531 | 532 | String packagePath = aarPackageName.replace('.', '/') 533 | 534 | 535 | 536 | // Generate the R.java file and map to current project's R.java 537 | 538 | // This will recreate the class file 539 | 540 | def rTxt = file("$aarPath/R.txt") 541 | 542 | def rMap = new ConfigObject() 543 | 544 | 545 | 546 | if (rTxt.exists()) { 547 | 548 | rTxt.eachLine { 549 | 550 | line -> 551 | 552 | //noinspection GroovyUnusedAssignment 553 | 554 | def (type, subclass, name, value) = line.tokenize(' ') 555 | 556 | try { 557 | if (rClassMap[subclass].containsKey(name)) { 558 | rMap[subclass].putAt(name, type) 559 | } 560 | } catch (Exception e) { 561 | e.printStackTrace() 562 | } 563 | 564 | } 565 | 566 | } 567 | 568 | 569 | 570 | def sb = "package $aarPackageName;" << '\n\n' 571 | 572 | sb << 'public final class R {' << '\n' 573 | 574 | 575 | 576 | rMap.each { 577 | 578 | subclass, values -> 579 | 580 | sb << " public static final class $subclass {" << '\n' 581 | 582 | values.each { 583 | 584 | name, type -> 585 | 586 | sb << " public static $type $name = ${export_package_name}.R.${subclass}.${name};" << '\n' 587 | 588 | } 589 | 590 | sb << " }" << '\n' 591 | 592 | } 593 | 594 | sb << '}' << '\n' 595 | 596 | 597 | 598 | mkdir("$generated_rsrc_dir/$packagePath") 599 | 600 | file("$generated_rsrc_dir/$packagePath/R.java").write(sb.toString()) 601 | 602 | println "====Generated R File: $generated_rsrc_dir/$packagePath/R.java" 603 | 604 | 605 | 606 | embeddedRClasses += "$packagePath/R.class" 607 | 608 | embeddedRClasses += "$packagePath/R\$*.class" 609 | 610 | } 611 | 612 | } 613 | 614 | } 615 | 616 | } 617 | 618 | 619 | 620 | task collectRClass { 621 | 622 | doLast { 623 | 624 | println "====Copy From: $classs_release_dir\n====Files: $embeddedRClasses\n--->To: $new_r_class_dir" 625 | 626 | delete new_r_class_dir 627 | 628 | mkdir new_r_class_dir 629 | 630 | 631 | 632 | copy { 633 | 634 | from classs_release_dir 635 | 636 | include embeddedRClasses 637 | 638 | into new_r_class_dir 639 | 640 | } 641 | 642 | } 643 | 644 | } 645 | 646 | 647 | 648 | task embedRClass(type: Jar, dependsOn: collectRClass) { 649 | 650 | println "====from : $new_r_class_dir\n====destinationDir: $extra_jar_dir" 651 | 652 | 653 | 654 | archiveName archiveNameOfRClasses 655 | 656 | destinationDir file(extra_jar_dir) 657 | 658 | from new_r_class_dir 659 | 660 | 661 | 662 | doLast { 663 | 664 | println "====Pack Jar(R*.class): $new_r_class_dir\n--->To: $extra_jar_dir" 665 | 666 | } 667 | 668 | } 669 | 670 | 671 | 672 | /** 673 | * To embed the class files, we need to change the R.class to X.class, so we explode it in another 674 | * location, proguard it to modify R to X, and then finally copy it to build location 675 | */ 676 | 677 | task embedJavaJars(dependsOn: embedRClass) { 678 | 679 | doLast { 680 | 681 | // Explode all classes.jar files to classes so that they can be proguarded 682 | 683 | println "1.Extra classes.jar from AAR" 684 | 685 | if (embeddedAarFiles.size() > 0) { 686 | 687 | embeddedAarFiles.each { artifact -> 688 | 689 | FileTree aarFileTree = zipTree(artifact.file.getAbsolutePath()) 690 | 691 | def aarFile = aarFileTree.files.find { it.name.contains("classes.jar") } 692 | 693 | 694 | 695 | println "====Copy classes.jar(in AAR): $artifact\n--->To: $classs_release_dir" 696 | 697 | copy { 698 | 699 | from zipTree(aarFile) 700 | 701 | into classs_release_dir 702 | 703 | } 704 | 705 | } 706 | 707 | } 708 | 709 | 710 | 711 | println "2.Extra dependended(.jar) from AAR" 712 | 713 | embeddedAarDirs.each { aarPath -> 714 | 715 | def jar_dir 716 | 717 | if (gradleApiVersion >= 2.3f) { 718 | 719 | jar_dir = "$aarPath" 720 | 721 | } else { 722 | 723 | jar_dir = "$aarPath/jars" 724 | 725 | } 726 | 727 | 728 | 729 | // Copy all additional & embedded jar files to bundle lib 730 | 731 | FileTree extraJars = fileTree(dir: jar_dir, include: '*.jar', exclude: 'classes.jar') 732 | 733 | extraJars += fileTree(dir: "$jar_dir/libs", include: '*.jar') 734 | 735 | extraJars += fileTree(dir: "$aarPath/libs", include: '*.jar') 736 | 737 | 738 | 739 | copy { 740 | 741 | if (extraJars.size() + embeddedJars.size() > 0) { 742 | 743 | println "====Copy jar files:" 744 | 745 | extraJars.each { fileItem -> 746 | 747 | println fileItem.absolutePath 748 | 749 | } 750 | 751 | 752 | 753 | if (embeddedJars.size() > 0) { 754 | 755 | println embeddedJars 756 | 757 | } 758 | 759 | println "--->To: $extra_jar_dir" 760 | 761 | } 762 | 763 | 764 | 765 | from extraJars, embeddedJars 766 | 767 | into extra_jar_dir 768 | 769 | } 770 | 771 | } 772 | 773 | } 774 | 775 | } 776 | 777 | 778 | 779 | task copyEmbedJars(type: Copy, dependsOn: embedJavaJars) { 780 | 781 | from extra_jar_dir 782 | 783 | into bundle_libs_dir 784 | 785 | 786 | 787 | doLast { 788 | 789 | println "====Copy jar files: $extra_jar_dir\n--->To: $bundle_libs_dir" 790 | 791 | } 792 | 793 | } 794 | 795 | 796 | 797 | /** 798 | * For some reason, adding to the jniLibs source set does not work. So we simply copy all files. 799 | */ 800 | 801 | task embedJniLibs { 802 | 803 | doLast { 804 | 805 | embeddedAarDirs.each { aarPath -> 806 | 807 | println "====Copy JNI files: $aarPath/jni\n-->To: $bundle_jni_dir" 808 | 809 | // Copy JNI Folders 810 | 811 | copy { 812 | 813 | from fileTree(dir: "$aarPath/jni") 814 | 815 | into bundle_jni_dir 816 | 817 | } 818 | 819 | } 820 | 821 | } 822 | 823 | } 824 | 825 | 826 | 827 | task embedManifests { 828 | 829 | doLast { 830 | 831 | ILogger mLogger = new MiLogger() 832 | 833 | List libraryManifests = new ArrayList<>() 834 | 835 | 836 | 837 | embeddedAarDirs.each { aarPath -> 838 | 839 | println "====Merge manifest $aarPath/AndroidManifest.xml" 840 | 841 | 842 | 843 | File dependencyManifest = file("$aarPath/AndroidManifest.xml") 844 | 845 | if (!libraryManifests.contains(aarPath) && dependencyManifest.exists()) { 846 | 847 | libraryManifests.add(dependencyManifest) 848 | 849 | } 850 | 851 | } 852 | 853 | 854 | 855 | File reportFile = file("${build_dir}/embedManifestReport.txt") 856 | 857 | 858 | 859 | File origManifest = file("$bundle_release_dir/AndroidManifest.xml") 860 | 861 | File copyManifest = file("$bundle_release_dir/AndroidManifest.orig.xml") 862 | 863 | File aaptManifest = file("$manifest_aapt_dir/AndroidManifest.xml") 864 | 865 | 866 | 867 | if (!origManifest.exists()) { 868 | 869 | origManifest = file("./src/main/AndroidManifest.xml") 870 | 871 | } 872 | 873 | 874 | 875 | if (!origManifest.exists()) { 876 | 877 | return 878 | 879 | } 880 | 881 | 882 | 883 | copy { 884 | 885 | from origManifest.parentFile 886 | 887 | into copyManifest.parentFile 888 | 889 | include origManifest.name 890 | 891 | rename(origManifest.name, copyManifest.name) 892 | 893 | } 894 | 895 | 896 | 897 | try { 898 | 899 | Invoker manifestMergerInvoker = ManifestMerger2.newMerger(copyManifest, mLogger, MergeType.APPLICATION) 900 | 901 | 902 | 903 | manifestMergerInvoker.addLibraryManifests(libraryManifests.toArray(new File[libraryManifests.size()])) 904 | 905 | 906 | 907 | // manifestMergerInvoker.setPlaceHolderValues(placeHolders) 908 | 909 | manifestMergerInvoker.setMergeReportFile(reportFile) 910 | 911 | 912 | 913 | MergingReport mergingReport = manifestMergerInvoker.merge() 914 | 915 | 916 | 917 | mLogger.info("Merging result:" + mergingReport.getResult()) 918 | 919 | MergingReport.Result result = mergingReport.getResult() 920 | 921 | switch (result) { 922 | 923 | case MergingReport.Result.WARNING: 924 | 925 | mergingReport.log(mLogger) 926 | 927 | // fall through since these are just warnings. 928 | 929 | case MergingReport.Result.SUCCESS: 930 | 931 | XmlDocument xmlDocument = mergingReport.getMergedXmlDocument(MergingReport.MergedManifestKind.MERGED) 932 | 933 | try { 934 | 935 | String annotatedDocument = mergingReport.getActions().blame(xmlDocument) 936 | 937 | mLogger.verbose(annotatedDocument) 938 | 939 | } catch (Exception e) { 940 | 941 | mLogger.error(e, "cannot print resulting xml") 942 | 943 | } 944 | 945 | save(xmlDocument, origManifest) 946 | 947 | mLogger.info("Merged manifest saved to " + origManifest) 948 | 949 | if (aaptManifest.exists()) { 950 | 951 | new PlaceholderEncoder().visit(xmlDocument) 952 | 953 | save(xmlDocument, aaptManifest) 954 | 955 | mLogger.info("Merged aapt safe manifest saved to " + aaptManifest) 956 | 957 | } 958 | 959 | break 960 | 961 | case MergingReport.Result.ERROR: 962 | 963 | mergingReport.log(mLogger) 964 | 965 | throw new RuntimeException(mergingReport.getReportString()) 966 | 967 | default: 968 | 969 | throw new RuntimeException("Unhandled result type : " + mergingReport.getResult()) 970 | 971 | } 972 | 973 | } catch (RuntimeException e) { 974 | 975 | // Unacceptable error 976 | 977 | e.printStackTrace() 978 | 979 | throw new RuntimeException(e) 980 | 981 | } 982 | 983 | } 984 | 985 | } 986 | 987 | 988 | 989 | private void save(XmlDocument xmlDocument, File out) { 990 | 991 | try { 992 | 993 | Files.write(xmlDocument.prettyPrint(), out, Charsets.UTF_8) 994 | 995 | } catch (IOException e) { 996 | 997 | throw new RuntimeException(e) 998 | 999 | } 1000 | 1001 | } 1002 | 1003 | 1004 | 1005 | class MiLogger implements ILogger { 1006 | 1007 | @Override 1008 | 1009 | void error( 1010 | 1011 | @com.android.annotations.Nullable Throwable t, 1012 | 1013 | @com.android.annotations.Nullable String msgFormat, Object... args) { 1014 | 1015 | System.err.println(String.format("========== ERROR : " + msgFormat, args)) 1016 | 1017 | if (t) t.printStackTrace(System.err) 1018 | 1019 | } 1020 | 1021 | 1022 | 1023 | @Override 1024 | 1025 | void warning(@NonNull String msgFormat, Object... args) { 1026 | 1027 | System.err.println(String.format("========== WARNING : " + msgFormat, args)) 1028 | 1029 | } 1030 | 1031 | 1032 | 1033 | @Override 1034 | 1035 | void info(@NonNull String msgFormat, Object... args) { 1036 | 1037 | System.out.println(String.format("========== INFO : " + msgFormat, args)) 1038 | 1039 | } 1040 | 1041 | 1042 | 1043 | @Override 1044 | 1045 | void verbose(@NonNull String msgFormat, Object... args) { 1046 | 1047 | // System.out.println(String.format("========== DEBUG : " + msgFormat, args)) 1048 | 1049 | } 1050 | 1051 | } 1052 | -------------------------------------------------------------------------------- /android/rn-library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android/rn-library/publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | 3 | publishing { 4 | publications { 5 | androidLibs(MavenPublication) { 6 | artifact bundleRelease 7 | 8 | List embedList = new ArrayList<>(); 9 | Map depList = new LinkedHashMap<>(); 10 | 11 | //List all embedded dependencies 12 | configurations.embedded.allDependencies.each { 13 | def depName = String.format("%s:%s", it.group, it.name) 14 | embedList.add(depName); 15 | } 16 | 17 | //Collect all first level dependencies except embedded ones 18 | configurations.compile.resolvedConfiguration.firstLevelModuleDependencies.each { 19 | ResolvedDependency dep -> 20 | def depName = String.format("%s:%s", dep.moduleGroup, dep.moduleName) 21 | if (!embedList.contains(depName) && !depList.containsKey(depName)) { 22 | depList.put(depName, dep) 23 | } 24 | } 25 | 26 | //Collect all second level dependencies of embedded ones 27 | configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies.each { 28 | //Second Level Depenencies 29 | it.children.each { 30 | ResolvedDependency dep -> 31 | def depName = String.format("%s:%s", dep.moduleGroup, dep.moduleName) 32 | if (!embedList.contains(depName) && !depList.containsKey(depName)) { 33 | depList.put(depName, dep) 34 | } 35 | } 36 | } 37 | 38 | //The publication doesn't know about our dependencies, so we have to manually add them to the pom 39 | pom.withXml { 40 | def dependenciesNode = asNode().appendNode('dependencies') 41 | 42 | //Iterate over the compile dependencies, adding a node for each 43 | depList.values().each { 44 | ResolvedDependency dep -> 45 | def hasGroup = dep.moduleGroup != null 46 | def hasName = (dep.moduleName != null || "unspecified".equals(dep.moduleName)) 47 | def hasVersion = dep.moduleVersion != null 48 | 49 | if (hasGroup && hasName && hasVersion) { 50 | def dependencyNode = dependenciesNode.appendNode('dependency') 51 | dependencyNode.appendNode('groupId', dep.moduleGroup) 52 | dependencyNode.appendNode('artifactId', dep.moduleName) 53 | dependencyNode.appendNode('version', dep.moduleVersion) 54 | } 55 | } 56 | } 57 | } 58 | } 59 | repositories { 60 | maven { 61 | url "/tmp/releases" 62 | // url "http://myserver/maven" 63 | credentials { 64 | username "1111" 65 | password "11111" 66 | } 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /android/rn-library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /android/rn-library/src/main/java/com/shuyu/rn/SingleActivity.java: -------------------------------------------------------------------------------- 1 | package com.shuyu.rn; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.KeyEvent; 6 | 7 | import com.airbnb.android.react.lottie.LottiePackage; 8 | import com.facebook.react.ReactInstanceManager; 9 | import com.facebook.react.ReactRootView; 10 | import com.facebook.react.bridge.NativeModuleCallExceptionHandler; 11 | import com.facebook.react.common.LifecycleState; 12 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 13 | import com.facebook.react.shell.MainReactPackage; 14 | import com.reactnative.photoview.PhotoViewPackage; 15 | 16 | 17 | public class SingleActivity extends Activity implements DefaultHardwareBackBtnHandler { 18 | 19 | ReactRootView mReactRootView; 20 | 21 | ReactInstanceManager mReactInstanceManager; 22 | 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | setContentView(R.layout.activity_single_layout); 29 | 30 | mReactRootView = (ReactRootView) findViewById(R.id.single_react_root_view); 31 | 32 | setReactNative(); 33 | } 34 | 35 | @Override 36 | public void invokeDefaultOnBackPressed() { 37 | super.onBackPressed(); 38 | } 39 | 40 | @Override 41 | protected void onPause() { 42 | super.onPause(); 43 | 44 | if (mReactInstanceManager != null) { 45 | mReactInstanceManager.onHostPause(this); 46 | } 47 | } 48 | 49 | @Override 50 | protected void onResume() { 51 | super.onResume(); 52 | 53 | if (mReactInstanceManager != null) { 54 | mReactInstanceManager.onHostResume(this, this); 55 | } 56 | } 57 | 58 | 59 | @Override 60 | protected void onDestroy() { 61 | super.onDestroy(); 62 | 63 | if (mReactInstanceManager != null) { 64 | mReactInstanceManager.onHostDestroy(this); 65 | } 66 | } 67 | 68 | 69 | @Override 70 | public void onBackPressed() { 71 | if (mReactInstanceManager != null) { 72 | mReactInstanceManager.onBackPressed(); 73 | } else { 74 | super.onBackPressed(); 75 | } 76 | } 77 | 78 | @Override 79 | public boolean onKeyUp(int keyCode, KeyEvent event) { 80 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 81 | mReactInstanceManager.showDevOptionsDialog(); 82 | return true; 83 | } 84 | return super.onKeyUp(keyCode, event); 85 | } 86 | 87 | 88 | private void setReactNative() { 89 | 90 | mReactInstanceManager = ReactInstanceManager.builder() 91 | .setApplication(this.getApplication()) 92 | .setBundleAssetName("index.android.bundle")//设置加载文件 93 | .setNativeModuleCallExceptionHandler(new NativeModuleCallExceptionHandler() { 94 | @Override 95 | public void handleException(Exception e) { 96 | e.printStackTrace(); 97 | } 98 | }) 99 | .addPackage(new MainReactPackage()) 100 | .addPackage(new LottiePackage()) 101 | .addPackage(new PhotoViewPackage()) 102 | .setJSMainModuleName("learnProject")// 103 | .setUseDeveloperSupport(false) 104 | .setInitialLifecycleState(LifecycleState.RESUMED) 105 | .build(); 106 | mReactRootView.startReactApplication(mReactInstanceManager, "learnProject", null);//启动入口 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /android/rn-library/src/main/res/layout/activity_single_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /android/rn-library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | rn-library 3 | 4 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'learnProject' 2 | include ':react-native-audio' 3 | project(':react-native-audio').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-audio/android') 4 | include ':lottie-react-native' 5 | project(':lottie-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/lottie-react-native/lib/android') 6 | include ':react-native-spinkit' 7 | project(':react-native-spinkit').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spinkit/android') 8 | include ':react-native-photo-view' 9 | project(':react-native-photo-view').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-photo-view/android') 10 | 11 | include ':app' 12 | include ':rn-library' 13 | include ':react-native-vector-icons' 14 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 15 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "learnProject", 3 | "displayName": "learnProject" 4 | } -------------------------------------------------------------------------------- /detail.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guoshuyu on 2017/2/20. 3 | */ 4 | 5 | import React, {Component} from 'react'; 6 | import { 7 | AppRegistry, 8 | View, 9 | Text, 10 | TouchableHighlight, 11 | Platform, 12 | ToastAndroid, 13 | Animated, 14 | Easing 15 | } from 'react-native'; 16 | 17 | import styles from './jscode/style/styles' 18 | 19 | import Animation from 'lottie-react-native'; 20 | 21 | import {NativeModules} from 'react-native'; 22 | const {DetailModule} = NativeModules; 23 | 24 | export default class detail extends Component { 25 | constructor(props) { 26 | super(props); 27 | //设置state 28 | this.state = { 29 | text1: 'detail, default text 1', 30 | text2: 'detail, default text 2', 31 | text3: 'detail, default text 3', 32 | text4: 'detail, default text 4', 33 | progress: new Animated.Value(0), 34 | } 35 | this.thisUnmount = false; 36 | } 37 | 38 | /** 39 | * 获取上一个Activity传递过来的数据 40 | * */ 41 | componentDidMount() { //这是React的生命周期函数,会在界面加载完成后执行一次 42 | DetailModule.getDataFromIntent( 43 | (successMsg1, successMsg2, successMsg3, successMsg4) => { 44 | this.setState({ 45 | text1: successMsg1, 46 | text2: successMsg2, 47 | text3: successMsg3, 48 | text4: successMsg4, 49 | }); //状态改变的话重新绘制界面 50 | }, 51 | (errorMsg) => { 52 | alert(errorMsg) 53 | } 54 | ); 55 | 56 | this.startAnimation(); 57 | } 58 | 59 | componentWillUnMount() { 60 | console.log("componentWillUnMount!!!"); 61 | this.thisUnmount = true; 62 | this.refs.AnimateCom.reset(); 63 | } 64 | 65 | startAnimation() { 66 | if (this.thisUnmount) { 67 | return; 68 | } 69 | Animated.timing(this.state.progress, { 70 | toValue: 1, 71 | duration: 5000, 72 | easing: Easing.linear 73 | }).start(({ finished }) => { 74 | console.log("had finished " + finished); 75 | if (!finished) { 76 | return; 77 | } 78 | console.log("restart"); 79 | //重复播放 80 | this.setState({ 81 | progress: new Animated.Value(0), 82 | }) 83 | this.startAnimation() 84 | }); 85 | } 86 | 87 | /** 88 | * 打开一个新的Activity,传递参数,页面销毁返回数据。 89 | * */ 90 | _clickItem() { 91 | DetailModule.startActivitySingle( 92 | (text) => { 93 | if (text) 94 | ToastAndroid.show('receive data from detail activity ' + text, 2000); 95 | }, 96 | (error) => { 97 | if (error) 98 | ToastAndroid.show('error data from detail activity ' + error, 2000); 99 | } 100 | ); 101 | 102 | } 103 | 104 | render() { 105 | return ( 106 | 107 | 108 | 109 | {this.state.text1} 110 | 111 | 112 | 113 | {this.state.text2} 114 | 115 | 116 | {this.state.text2} 117 | 118 | 119 | {this.state.text4} 120 | 121 | 122 | 131 | 132 | ); 133 | 134 | } 135 | } -------------------------------------------------------------------------------- /home.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guoshuyu on 2017/2/6. 3 | */ 4 | import React, { Component } from 'react'; 5 | import { 6 | AppRegistry, 7 | StyleSheet, 8 | } from 'react-native'; 9 | import { Provider } from 'react-redux'; 10 | 11 | import configureStore from './jscode/store/index'; 12 | 13 | import detail from './detail' 14 | 15 | let store = configureStore(); 16 | 17 | import * as RouterUtils from './jscode/common/router'; 18 | 19 | class home extends Component { 20 | 21 | constructor(){ 22 | super(); 23 | this.state = { 24 | store: configureStore() 25 | } 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | {RouterUtils.getRouter()} 32 | 33 | ); 34 | } 35 | } 36 | 37 | export default home; 38 | 39 | //将需要打开的activity关联的js注册进来 40 | AppRegistry.registerComponent('detail', () => detail); -------------------------------------------------------------------------------- /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 | } from 'react-native'; 11 | import Home from './home' 12 | 13 | 14 | export default class learnProject extends Component { 15 | 16 | render() { 17 | return ( 18 | 19 | ); 20 | } 21 | } 22 | AppRegistry.registerComponent('learnProject', () => learnProject); 23 | -------------------------------------------------------------------------------- /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 | } from 'react-native'; 11 | import Home from './home' 12 | 13 | 14 | export default class learnProject extends Component { 15 | 16 | render() { 17 | return ( 18 | 19 | ); 20 | } 21 | } 22 | AppRegistry.registerComponent('learnProject', () => learnProject); 23 | -------------------------------------------------------------------------------- /ios/learnProject-tvOS/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 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ios/learnProject-tvOSTests/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 | -------------------------------------------------------------------------------- /ios/learnProject.xcodeproj/xcshareddata/xcschemes/learnProject-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/learnProject.xcodeproj/xcshareddata/xcschemes/learnProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/learnProject/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 | -------------------------------------------------------------------------------- /ios/learnProject/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 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"learnProject" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/learnProject/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 | -------------------------------------------------------------------------------- /ios/learnProject/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 | } -------------------------------------------------------------------------------- /ios/learnProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | learnProject 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | NSMicrophoneUsageDescription 34 | This sample uses the microphone to record your speech and convert it to text. 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UIViewControllerBasedStatusBarAppearance 42 | 43 | NSLocationWhenInUseUsageDescription 44 | 45 | NSAppTransportSecurity 46 | 47 | NSExceptionDomains 48 | 49 | localhost 50 | 51 | NSExceptionAllowsInsecureHTTPLoads 52 | 53 | 54 | 55 | 56 | UIAppFonts 57 | 58 | Entypo.ttf 59 | EvilIcons.ttf 60 | FontAwesome.ttf 61 | Foundation.ttf 62 | Ionicons.ttf 63 | MaterialCommunityIcons.ttf 64 | MaterialIcons.ttf 65 | Octicons.ttf 66 | SimpleLineIcons.ttf 67 | Zocial.ttf 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ios/learnProject/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 | -------------------------------------------------------------------------------- /ios/learnProjectTests/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 | -------------------------------------------------------------------------------- /ios/learnProjectTests/learnProjectTests.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 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface learnProjectTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation learnProjectTests 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 | -------------------------------------------------------------------------------- /jscode/actions/counter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guoshuyu on 2017/2/12. 3 | */ 4 | export const INCREMENT = 'INCREMENT'; 5 | export const DECREMENT = 'DECREMENT'; 6 | 7 | export function increment() { 8 | return { 9 | type: INCREMENT 10 | }; 11 | } 12 | 13 | export function decrement() { 14 | return { 15 | type: DECREMENT 16 | }; 17 | } -------------------------------------------------------------------------------- /jscode/common/router.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { 3 | AppRegistry, 4 | StyleSheet, 5 | Navigator, 6 | Platform, 7 | } from 'react-native'; 8 | import { 9 | Scene, 10 | Router, 11 | Modal 12 | } from 'react-native-router-flux'; 13 | 14 | import Page2 from '../components/page2' 15 | import PhotoView from '../components/PhotoView' 16 | import TabIcon from '../../jscode/components/widget/tabIcon'; 17 | import {iosNav, androidNav, tabBarHeight} from '../style/styles' 18 | import TabListPage from '../../jscode/components/tabListPage'; 19 | 20 | //设置router的样式 21 | const getSceneStyle = (props, computedProps) => { 22 | 23 | const style = { 24 | flex: 1, 25 | backgroundColor: '#fff', 26 | shadowColor: null, 27 | shadowOffset: null, 28 | shadowOpacity: null, 29 | shadowRadius: null, 30 | }; 31 | 32 | //因为tab和navBar会overlap,导致被遮挡看不到,所以需要设置padding 33 | if (computedProps.isActive) { 34 | style.paddingTop = computedProps.hideNavBar ? 0 : (Platform.OS == 'ios' ? iosNav : androidNav); 35 | style.paddingBottom = computedProps.hideTabBar ? 0 : tabBarHeight; 36 | } 37 | return style; 38 | }; 39 | 40 | 41 | export const getRouter = () => { 42 | return ( 43 | 44 | 45 | 46 | 55 | 62 | 69 | 70 | 71 | 72 | 73 | 74 | ) 75 | }; 76 | -------------------------------------------------------------------------------- /jscode/components/PhotoView.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import { 3 | Text, 4 | View, 5 | Image, 6 | TouchableOpacity, 7 | TouchableWithoutFeedback, 8 | Dimensions, 9 | ActivityIndicator, 10 | } from 'react-native' 11 | import Swiper from 'react-native-swiper' 12 | import PhotoView from 'react-native-photo-view' 13 | 14 | import {Actions} from "react-native-router-flux"; 15 | import Styles from '../style/styles' 16 | 17 | const {width, height} = Dimensions.get('window'); 18 | 19 | var styles = { 20 | wrapper: { 21 | backgroundColor: '#000', 22 | top: 0, 23 | right: 0, 24 | bottom: 0, 25 | left: 0 26 | }, 27 | slide: { 28 | flex: 1, 29 | justifyContent: 'center', 30 | alignItems: 'center' 31 | }, 32 | photo: { 33 | width, 34 | height, 35 | flex: 1 36 | }, 37 | text: { 38 | color: '#fff', 39 | fontSize: 30, 40 | fontWeight: 'bold' 41 | }, 42 | thumbWrap: { 43 | marginTop: 100, 44 | borderWidth: 5, 45 | borderColor: '#000', 46 | flexDirection: 'row' 47 | }, 48 | thumb: { 49 | width: 50, 50 | height: 50 51 | } 52 | } 53 | 54 | const renderPagination = (index, total, context) => { 55 | return ( 56 | 64 | 70 | {index + 1} / {total} 74 | 75 | 76 | ) 77 | } 78 | 79 | 80 | const Viewer = props => 81 | { 82 | props.imgList.map((item, i) => 83 | 88 | ) 89 | } 90 | 91 | 92 | 93 | class PhotoViewItemVier extends Component { 94 | constructor(props) { 95 | super(props) 96 | this.state = { 97 | imageLoaded: true 98 | } 99 | } 100 | 101 | componentDidMount() { 102 | this.mount = true; 103 | } 104 | 105 | componentWillUnmount() { 106 | this.mount = false; 107 | } 108 | 109 | render() { 110 | let loading = (this.state.imageLoaded) ? 111 | 112 | 114 | 119 | : 120 | return ( 121 | 122 | 132 | {loading} 133 | 134 | ) 135 | } 136 | 137 | onLoadStart(e) { 138 | if (this.mount == true) { 139 | setTimeout(() => { 140 | this.setState({ 141 | imageLoaded: true 142 | }); 143 | }, 50); 144 | } 145 | } 146 | 147 | onLoad(e) { 148 | if (this.mount == true) { 149 | setTimeout(() => { 150 | this.setState({ 151 | imageLoaded: false 152 | }); 153 | }, 50); 154 | } 155 | } 156 | } 157 | 158 | class PhotoComponent extends Component { 159 | constructor(props) { 160 | super(props); 161 | let {i} = this.props.selectPosition; 162 | this.state = { 163 | imgList: this.props.imgData, 164 | showViewer: true, 165 | showIndex: i, 166 | }; 167 | this.thumbPressHandle = this.thumbPressHandle.bind(this); 168 | this.viewerPressHandle = this.viewerPressHandle.bind(this); 169 | } 170 | 171 | thumbPressHandle(i) { 172 | this.setState({ 173 | showIndex: i, 174 | showViewer: true 175 | }) 176 | } 177 | 178 | viewerPressHandle() { 179 | Actions.pop(); 180 | } 181 | 182 | render() { 183 | return ( 184 | {this.state.showViewer && } 188 | 189 | { 190 | this.state.imgList.map((item, i) => this.thumbPressHandle(i)}> 192 | 193 | ) 194 | } 195 | 196 | ) 197 | } 198 | } 199 | 200 | export default PhotoComponent; -------------------------------------------------------------------------------- /jscode/components/meteorListView.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; 3 | import Meteor, { connectMeteor, MeteorListView } from 'react-native-meteor'; 4 | import Button from './widget/button'; 5 | 6 | @connectMeteor 7 | class MeteorListViewComponent extends Component { 8 | 9 | getMeteorData() { 10 | const itemsHandle = Meteor.subscribe('items'); 11 | return { 12 | itemsReady: itemsHandle.ready() 13 | }; 14 | } 15 | 16 | renderRow(item) { 17 | return ( 18 | 19 | {item.name} 20 | Meteor.call('removeItem', item._id)}> 21 | X 22 | 23 | 24 | ); 25 | } 26 | 27 | render() { 28 | const { itemsReady } = this.data; 29 | if (!itemsReady) { 30 | return ( 31 | 32 | Loading... 33 | 34 | ) 35 | } 36 | 37 | return ( 38 | 39 | 40 |