├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── ids.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_test_view.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── activity_welcome.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── cmacking
│ │ │ │ └── reactnativeandroiddemo
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── util
│ │ │ │ ├── ThemeUtile.java
│ │ │ │ └── JSONHelper.java
│ │ │ │ ├── RnView
│ │ │ │ ├── TestViewActivity.java
│ │ │ │ ├── CommonActivity.java
│ │ │ │ └── MyRnViewActivity.java
│ │ │ │ ├── MyReactPackage.java
│ │ │ │ ├── MainApplication.java
│ │ │ │ ├── MyActivity.java
│ │ │ │ ├── WelcomeActivity.java
│ │ │ │ └── MyIntentModule.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── cmacking
│ │ │ └── reactnativeandroiddemo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── cmacking
│ │ └── reactnativeandroiddemo
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── .gitattributes
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── vcs.xml
├── runConfigurations.xml
├── gradle.xml
├── misc.xml
└── codeStyles
│ └── Project.xml
├── settings.gradle
├── .gitignore
├── index.js
├── package.json
├── gradle.properties
├── README.md
├── src
├── TestView.js
├── RnCommonActivity.js
├── GetAllNativeModules.js
└── HelloWorld.js
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | .js linguist-language=JavaScript
2 | .java linguist-language=Android
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itenl/ReactNativeAndroidDemo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':react-native-android-fragment'
3 | project(':react-native-android-fragment').projectDir = new File(rootProject.projectDir, 'node_modules/react-native-android-fragment/android')
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | /.idea/caches
8 | /node_modules
9 | .DS_Store
10 | /build
11 | /captures
12 | .externalNativeBuild
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - btn_jumpactivity_str
4 | - btn_change_theme_str
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 14 18:12:19 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #21B0DF
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | public class MainActivity extends AppCompatActivity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/cmacking/reactnativeandroiddemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from 'react-native';
2 | import HelloWorld from './src/HelloWorld';
3 | import TestView from './src/TestView';
4 | import GetAllNativeModules from './src/GetAllNativeModules';
5 | import RnCommonActivity from './src/RnCommonActivity';
6 |
7 | AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
8 | AppRegistry.registerComponent('TestView', () => TestView);
9 | AppRegistry.registerComponent('GetAllNativeModules', () => GetAllNativeModules);
10 |
11 | AppRegistry.registerComponent('RnCommonActivity', () => RnCommonActivity);
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/util/ThemeUtile.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo.util;
2 |
3 | import android.app.Activity;
4 |
5 | import com.example.cmacking.reactnativeandroiddemo.R;
6 |
7 | /**
8 | * 切换主题——工具
9 | */
10 |
11 | public class ThemeUtile {
12 |
13 | public static boolean night = false;
14 |
15 |
16 | public static void changeTheme(Activity activity){
17 | if (ThemeUtile.night){
18 | activity.setTheme(R.style.APPThemeNight);
19 | }else{
20 | activity.setTheme(R.style.AppTheme);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_native_demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "start-by-custom": "node node_modules/react-native/local-cli/cli.js start --port 8082 --host 172.17.3.3",
8 | "test": "jest"
9 | },
10 | "dependencies": {
11 | "react": "16.4.1",
12 | "react-native": "0.56.0",
13 | "react-native-android-fragment": "^1.1.0"
14 | },
15 | "devDependencies": {
16 | "babel-jest": "23.4.2",
17 | "babel-preset-react-native": "^5",
18 | "jest": "23.5.0",
19 | "react-test-renderer": "16.4.1"
20 | },
21 | "jest": {
22 | "preset": "react-native"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReactNativeAndroidDemo
2 |
3 | ReactNative 基于 Android 中的集成、两端事件调用、Fragment 集成、Callback/Promise 使用
4 |
5 | ## Usage
6 |
7 | step 1:通过 clone 本项目后 `npm install` 安装相关依赖;
8 |
9 | step 2:修改 `~/ReactNativeAndroidDemo/local.properties` 下的 `sdk.dir=/Users/[your computer name]/Library/Android/sdk` ;
10 |
11 | step 3:`npm start` 即可
12 |
13 | ```javascript
14 | NativeModules.MyIntentModule.startActivityFromJSGetResult(
15 | 'com.example.cmacking.reactnativeandroiddemo.MyActivity',
16 | 200,
17 | msg => {
18 | ToastAndroid.show(
19 | 'JS界面:从Activity中传输过来的数据为:' + msg,
20 | ToastAndroid.SHORT
21 | );
22 | },
23 | result => {
24 | ToastAndroid.show('JS界面:错误信息为:' + result, ToastAndroid.SHORT);
25 | }
26 | );
27 |
28 | 项目中使用的 [com.example.cmacking...] 为 Android 项目命名空间
29 | ```
30 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/cmacking/reactnativeandroiddemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.cmacking.reactnativeandroiddemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/RnView/TestViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo.RnView;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.example.cmacking.reactnativeandroiddemo.R;
7 | import com.facebook.react.ReactActivity;
8 |
9 | //public class TestViewActivity extends AppCompatActivity {
10 | //
11 | // @Override
12 | // protected void onCreate(Bundle savedInstanceState) {
13 | // super.onCreate(savedInstanceState);
14 | // setContentView(R.layout.activity_test_view2);
15 | // }
16 | //}
17 |
18 | public class TestViewActivity extends ReactActivity {
19 |
20 | /**
21 | * Returns the name of the main component registered from JavaScript.
22 | * This is used to schedule rendering of the component.
23 | */
24 | @Override
25 | protected String getMainComponentName() {
26 | return "TestView";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/TestView.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StyleSheet,
4 | Text,
5 | View,
6 | NativeModules,
7 | TouchableNativeFeedback,
8 | Button,
9 | ToastAndroid
10 | } from 'react-native';
11 |
12 | class TestView extends React.Component {
13 | render() {
14 | return (
15 |
16 |
27 | );
28 | }
29 | }
30 | var styles = StyleSheet.create({
31 | container: {
32 | flex: 1,
33 | justifyContent: 'center'
34 | },
35 | hello: {
36 | fontSize: 20,
37 | textAlign: 'center',
38 | margin: 10
39 | }
40 | });
41 |
42 | export default TestView;
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/MyReactPackage.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | /**
14 | * 注册模块
15 | */
16 |
17 | public class MyReactPackage implements ReactPackage {
18 | @Override
19 | public List createNativeModules(ReactApplicationContext reactContext) {
20 | // List modules = new ArrayList<>();
21 | // modules.add(new MyIntentModule(reactContext));
22 | // return modules;
23 |
24 | return Arrays.asList(new MyIntentModule(reactContext));
25 | }
26 | @Override
27 | public List createViewManagers(ReactApplicationContext reactContext) {
28 | return Collections.emptyList();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/RnCommonActivity.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StyleSheet,
4 | Text,
5 | View,
6 | NativeModules,
7 | TouchableNativeFeedback,
8 | ToastAndroid
9 | } from 'react-native';
10 | import HelloWorld from './HelloWorld';
11 | import TestView from './TestView';
12 | import GetAllNativeModules from './GetAllNativeModules';
13 |
14 | class RnCommonActivity extends React.Component {
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | test: 'RnCommonActivity'
19 | };
20 | }
21 |
22 | render() {
23 | switch (this.props.COMPONENT_TYPE) {
24 | case 'HelloWorld':
25 | return ;
26 | case 'TestView':
27 | return ;
28 | case 'GetAllNativeModules':
29 | return ;
30 | default:
31 | return (
32 |
33 | {this.props.COMPONENT_TYPE}
34 |
35 | );
36 | }
37 | }
38 | }
39 |
40 | export default RnCommonActivity;
41 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.example.cmacking.reactnativeandroiddemo"
7 | minSdkVersion 16
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | // testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:27.1.1'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | testImplementation 'junit:junit:4.12'
26 |
27 | // androidTestImplementation 'com.android.support.test:runner:1.0.2'
28 | // androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
29 |
30 | implementation 'com.facebook.react:react-native:+'
31 | implementation project(':react-native-android-fragment')
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ReactNativeAndroidDemo
3 | This is Home View
4 | Dashboard
5 | Notifications
6 | 切换主题
7 | My Activity
8 | Sign in
9 |
10 |
11 | Email
12 | Password (optional)
13 | Sign in or register
14 | Sign in
15 | This email address is invalid
16 | This password is too short
17 | This password is incorrect
18 | This field is required
19 | "Contacts permissions are needed for providing email
20 | completions."
21 |
22 | 跳转到Rn页
23 |
24 |
--------------------------------------------------------------------------------
/src/GetAllNativeModules.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StyleSheet,
4 | Text,
5 | View,
6 | NativeModules,
7 | TouchableNativeFeedback,
8 | Button,
9 | ScrollView,
10 | ToastAndroid
11 | } from 'react-native';
12 |
13 | class GetAllNativeModules extends React.Component {
14 | constructor(props) {
15 | super(props);
16 | }
17 | getAllNativeModules() {
18 | const nativeModules = NativeModules;
19 | let text = [];
20 | Object.keys(nativeModules).map((key, index, items) => {
21 | let val=nativeModules[key];
22 | text.push(
23 |
24 | {key}
25 | {JSON.stringify(val)}
26 | ====================================
27 |
28 | );
29 | });
30 | return text;
31 | }
32 |
33 | render() {
34 | return (
35 |
36 | {/* GetAllNativeModules 得到 NativeModules 所有模块 */}
37 | {this.props.COMPONENT_TYPE}
38 | {this.getAllNativeModules()}
39 |
40 | );
41 | }
42 | }
43 | var styles = StyleSheet.create({
44 | container: {
45 | flex: 1
46 | // justifyContent: 'center'
47 | },
48 | hello: {
49 | fontSize: 20,
50 | textAlign: 'center',
51 | margin: 10
52 | }
53 | });
54 |
55 | export default GetAllNativeModules;
56 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_welcome.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
19 |
20 |
27 |
28 |
34 |
35 |
41 |
42 |
46 |
47 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/RnView/CommonActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo.RnView;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.widget.Toast;
7 |
8 | import com.example.cmacking.reactnativeandroiddemo.MainApplication;
9 | import com.facebook.react.ReactActivity;
10 | import com.facebook.react.ReactActivityDelegate;
11 |
12 | import java.util.concurrent.ArrayBlockingQueue;
13 |
14 | public class CommonActivity extends ReactActivity {
15 | //构建一个阻塞的单一数据的队列
16 | // public static ArrayBlockingQueue mQueue = new ArrayBlockingQueue(1);
17 |
18 | private static String COMPONENT_TYPE = "";
19 |
20 | /**
21 | * Returns the name of the main component registered from JavaScript.
22 | * This is used to schedule rendering of the component.
23 | */
24 | @Override
25 | protected String getMainComponentName() {
26 | return "RnCommonActivity";
27 | }
28 |
29 | //
30 | // @Override
31 | // protected void onCreate(Bundle savedInstanceState) {
32 | // super.onCreate(savedInstanceState);
33 | // COMPONENT_TYPE = this.getIntent().getStringExtra("COMPONENT_TYPE");
34 | // }
35 |
36 | @Override
37 | protected ReactActivityDelegate createReactActivityDelegate() {
38 | return new ReactActivityDelegate(this, getMainComponentName()) {
39 | @Nullable
40 | @Override
41 | protected Bundle getLaunchOptions() {
42 | // Bundle bundle = new Bundle();
43 | // bundle.putString("COMPONENT_TYPE", COMPONENT_TYPE);
44 | // return bundle;
45 | return MainApplication.getRnCommonActivityBundle();
46 | }
47 | };
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.app.Application;
4 | import android.os.Bundle;
5 |
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.shell.MainReactPackage;
10 | import com.facebook.soloader.SoLoader;
11 |
12 | import java.util.Arrays;
13 | import java.util.HashMap;
14 | import java.util.List;
15 |
16 | public class MainApplication extends Application implements ReactApplication {
17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
18 |
19 | /**
20 | * Returns whether dev mode should be enabled.
21 | * This enables e.g. the dev menu.
22 | */
23 | @Override
24 | public boolean getUseDeveloperSupport() {
25 | return BuildConfig.DEBUG;
26 | }
27 |
28 | /**
29 | * A list of packages used by the app. If the app uses additional views
30 | * or modules besides the default ones, add more packages here.
31 | */
32 | @Override
33 | protected List getPackages() {
34 | return Arrays.asList(
35 | new MainReactPackage(),
36 | new MyReactPackage()
37 | );
38 | }
39 |
40 | @Override
41 | protected String getJSMainModuleName() {
42 | return "index";
43 | }
44 |
45 | };
46 |
47 | @Override
48 | public ReactNativeHost getReactNativeHost() {
49 | return mReactNativeHost;
50 | }
51 |
52 | @Override
53 | public void onCreate() {
54 | super.onCreate();
55 | SoLoader.init(this, /* native exopackage */ false);
56 | }
57 |
58 | private static Bundle sBundle;
59 | private static HashMap hashMap;
60 |
61 | public static void setRnCommonActivityInitProps(int entrance) {
62 | if (hashMap == null) {
63 | hashMap = new HashMap();
64 | hashMap.put(1, "HelloWorld");
65 | hashMap.put(2, "TestView");
66 | hashMap.put(3, "GetAllNativeModules");
67 | }
68 | sBundle = new Bundle();
69 | sBundle.putString("COMPONENT_TYPE", hashMap.get(entrance).toString());
70 | }
71 |
72 | public static void setRnCommonActivityInitProps(String entrance) {
73 | sBundle = new Bundle();
74 | sBundle.putString("COMPONENT_TYPE", entrance);
75 | }
76 |
77 | public static Bundle getRnCommonActivityBundle() {
78 | return sBundle;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/MyActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.Gravity;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.LinearLayout;
11 | import android.widget.RelativeLayout;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.example.cmacking.reactnativeandroiddemo.util.ThemeUtile;
16 |
17 | /**
18 | * 1、 原生页面与RN 跳转交互
19 | * 2、 黑白主题切换
20 | */
21 |
22 | public class MyActivity extends Activity implements View.OnClickListener {
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | ThemeUtile.changeTheme(this);
28 | setContentView(createView());
29 | }
30 |
31 | private View createView() {
32 | LinearLayout ll = new LinearLayout(this);
33 | ll.setGravity(Gravity.CENTER);
34 | ll.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
35 | // 设置文字
36 | TextView mTextView = new TextView(this);
37 | mTextView.setText("hello world 这里是原生页面:MyActivity");
38 | // TypedValue typedValue = new TypedValue();
39 | // getTheme().resolveAttribute(R.attr.Text_bg_Color, typedValue, true);
40 | // mTextView.setBackgroundColor(typedValue.resourceId);
41 |
42 | //设置按钮
43 | Button mButton = new Button(this);
44 | mButton.setId(R.id.btn_change_theme);
45 | mButton.setText(R.string.change_theme);
46 | mButton.setOnClickListener(this);
47 |
48 | //设置按钮
49 | Button mButton_jump = new Button(this);
50 | mButton_jump.setId(R.id.btn_jumpactivity);
51 | mButton_jump.setText(R.string.jump_activity);
52 | mButton_jump.setOnClickListener(this);
53 |
54 |
55 | LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(
56 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
57 |
58 | // 在父类布局中添加它,及布局样式
59 | ll.addView(mTextView, mLayoutParams);
60 | ll.addView(mButton, mLayoutParams);
61 | ll.addView(mButton_jump, mLayoutParams);
62 |
63 |
64 | return ll;
65 |
66 | }
67 |
68 |
69 | @Override
70 | public void onClick(View v) {
71 | switch (v.getId()) {
72 | case R.id.btn_change_theme:
73 | if (ThemeUtile.night) {
74 | ThemeUtile.night = false;
75 | } else {
76 | ThemeUtile.night = true;
77 | }
78 | recreate();
79 | break;
80 | case R.id.btn_jumpactivity:
81 | Intent mIntent = new Intent();
82 | mIntent.putExtra("get_result", "From Activity的数据回调过来啦~");
83 | MyActivity.this.setResult(Activity.RESULT_OK, mIntent);
84 | MyActivity.this.finish();
85 | break;
86 | default:
87 | break;
88 | }
89 |
90 | //出现问题:由于在当前屏幕值重新设置主题,会导致重新调用onCreate()方法导致闪屏
91 |
92 | /**
93 | * 解决方案1:
94 | * 可以在一个新开的Activity中通过ThemeUtile.night变量重新设置主题,但不调用recreate()方法切换主题,
95 | * 而是“手动”设置需要改变的属性,在退出该Activity时,使用Intent回到之前的界面,
96 | * 并 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
97 | * ,使之前的Activity全部出栈,重新创建一个新的Activity,执行onCreate()方法,从而改变主题。
98 | * 虽然不是很优雅,但是完成了不闪屏切换Android App主题。
99 | */
100 | }
101 | }
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/WelcomeActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.app.Activity;
4 | import android.app.ActivityManager;
5 | import android.content.Intent;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.KeyEvent;
11 | import android.view.View;
12 | import android.widget.Button;
13 | import android.widget.Toast;
14 |
15 | import com.example.cmacking.reactnativeandroiddemo.RnView.CommonActivity;
16 | import com.example.cmacking.reactnativeandroiddemo.RnView.MyRnViewActivity;
17 | import com.example.cmacking.reactnativeandroiddemo.RnView.TestViewActivity;
18 | import com.facebook.react.ReactInstanceManager;
19 | import com.facebook.react.ReactRootView;
20 | import com.facebook.react.common.LifecycleState;
21 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
22 | import com.facebook.react.shell.MainReactPackage;
23 | import com.hudl.oss.react.fragment.ReactFragment;
24 |
25 | import java.util.HashMap;
26 | import java.util.Stack;
27 |
28 | public class WelcomeActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
29 |
30 | private static final String COMPONENT_FRAGMENT_NAME = "HelloWorld";//HelloWorld TestView GetAllNativeModules
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_welcome);
36 | Activity currentActivity = this;
37 | String result = currentActivity.getIntent().getStringExtra("params");
38 | Toast.makeText(this, "Android.WelComeActivity.onCreate.params:" + result, Toast.LENGTH_SHORT).show();
39 | Button btn_welcome = (Button) this.findViewById(R.id.btn_welcome);
40 | Button btn_testview = (Button) this.findViewById(R.id.btn_testview);
41 | Button btn_rncommonactivity = (Button) this.findViewById(R.id.btn_rncommonactivity);
42 | btn_welcome.setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | Intent mIntent = new Intent(WelcomeActivity.this, MyRnViewActivity.class);
46 | // mIntent.putExtra("","");
47 | WelcomeActivity.this.startActivity(mIntent);
48 | }
49 | });
50 | btn_testview.setOnClickListener(new View.OnClickListener() {
51 | @Override
52 | public void onClick(View v) {
53 | Intent mIntent = new Intent(WelcomeActivity.this, TestViewActivity.class);
54 | WelcomeActivity.this.startActivity(mIntent);
55 | }
56 | });
57 |
58 | //通过公共页 随机跳转到 Rn 页
59 | btn_rncommonactivity.setOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View v) {
62 | int num = (int) ((Math.random() * 3 + 1));
63 | MainApplication.setRnCommonActivityInitProps(num);
64 | Intent mIntent = new Intent(WelcomeActivity.this, CommonActivity.class);
65 | // mIntent.putExtra("COMPONENT_TYPE","TestView");
66 | WelcomeActivity.this.startActivity(mIntent);
67 | }
68 | });
69 |
70 |
71 | // ActivityManager sd = (ActivityManager) this.getSystemService(this.ACTIVITY_SERVICE);
72 |
73 | if (savedInstanceState == null) {
74 | Bundle bundle = new Bundle();
75 | // FRAGMENT 传参
76 | bundle.putString("msg", "{\"test\":123,\"str\":\"HelloWorld this message from Android_WelcomeActivity_Fragment\"}");
77 | ReactFragment reactFragment = new ReactFragment.Builder(COMPONENT_FRAGMENT_NAME).setLaunchOptions(bundle).build();
78 |
79 | getSupportFragmentManager()
80 | .beginTransaction()
81 | .add(R.id.layout_welcome, reactFragment)
82 | .commit();
83 | }
84 |
85 |
86 | }
87 |
88 | @Override
89 | public void invokeDefaultOnBackPressed() {
90 | super.onBackPressed();
91 | }
92 |
93 | /**
94 | * Forward onKeyUp events to the ReactFragment in order to handle double tap reloads
95 | * and dev menus
96 | *
97 | * @param keyCode
98 | * @param event
99 | * @return true if event was handled
100 | */
101 | @Override
102 | public boolean onKeyUp(int keyCode, KeyEvent event) {
103 | boolean handled = false;
104 | Fragment activeFragment = getSupportFragmentManager().findFragmentById(R.id.layout_welcome);
105 | if (activeFragment instanceof ReactFragment) {
106 | handled = ((ReactFragment) activeFragment).onKeyUp(keyCode, event);
107 | }
108 | return handled || super.onKeyUp(keyCode, event);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/HelloWorld.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StyleSheet,
4 | Text,
5 | View,
6 | NativeModules,
7 | TouchableNativeFeedback,
8 | ToastAndroid
9 | } from 'react-native';
10 |
11 | class HelloWorld extends React.Component {
12 | constructor(props) {
13 | super(props);
14 | this.state = {
15 | test: '123456'
16 | };
17 | }
18 |
19 | // _onPressButton() {
20 | // console.log('You tapped the _onPressButton!');
21 | // NativeModules.MyIntentModule.startActivityFromJS(
22 | // 'com.example.cmacking.reactnativeandroiddemo.MyActivity',
23 | // '我是RN HelloWorld 的页面数据'
24 | // );
25 | // }
26 |
27 | // _onPressButtonByData() {
28 | // console.log('You tapped the _onPressButtonByData!');
29 | // NativeModules.MyIntentModule.dataToJS(
30 | // msg => {
31 | // console.log(msg);
32 | // ToastAndroid.show(
33 | // 'JS界面:从Activity中传输过来的数据为:' + msg,
34 | // ToastAndroid.SHORT
35 | // );
36 | // },
37 | // result => {
38 | // ToastAndroid.show('JS界面:错误信息为:' + result, ToastAndroid.SHORT);
39 | // }
40 | // );
41 | // }
42 |
43 | // _onPressButtonByNativeToast() {
44 | // NativeModules.MyIntentModule.show(
45 | // 'Rn调用原生Toash方法及常量:' + NativeModules.MyIntentModule.OBJ,
46 | // NativeModules.MyIntentModule.LONG
47 | // );
48 | // alert('JS INVOKE OVER');
49 | // }
50 |
51 | // async _onPressButtonByTestPromise() {
52 | // try {
53 | // var {
54 | // relativeX,
55 | // relativeY,
56 | // width,
57 | // height,
58 | // } = await NativeModules.MyIntentModule.testPromise(10, 100);
59 | // alert(relativeX + ':' + relativeY + ':' + width + ':' + height);
60 | // } catch (e) {
61 | // console.error(e);
62 | // }
63 | // }
64 |
65 | render() {
66 | return (
67 |
68 | Hello, World 这里是RN页面
69 |
70 | bundle:
71 | {this.props.bundle}
72 |
73 |
74 | msg:
75 | {this.props.msg &&
76 | JSON.parse(this.props.msg).test + JSON.parse(this.props.msg).str}
77 |
78 | {
80 | NativeModules.MyIntentModule.startActivityFromJS(
81 | 'com.example.cmacking.reactnativeandroiddemo.MyActivity',
82 | '我是RN HelloWorld 的页面数据'
83 | );
84 | }}
85 | >
86 | 跳转到原生页面 MyActivity
87 |
88 | {
90 | NativeModules.MyIntentModule.startActivityFromJSGetResult(
91 | 'com.example.cmacking.reactnativeandroiddemo.MyActivity',
92 | 200,
93 | msg => {
94 | ToastAndroid.show(
95 | 'JS界面:从Activity中传输过来的数据为:' + msg,
96 | ToastAndroid.SHORT
97 | );
98 | },
99 | result => {
100 | ToastAndroid.show(
101 | 'JS界面:错误信息为:' + result,
102 | ToastAndroid.SHORT
103 | );
104 | }
105 | );
106 | }}
107 | >
108 |
109 | 跳转到原生页面 MyActivity,支持在 MyActivity 跳转回来接收 Intent
110 | 的传参
111 |
112 |
113 | {
115 | NativeModules.MyIntentModule.dataToJS(
116 | msg => {
117 | console.log(msg);
118 | ToastAndroid.show(
119 | 'JS界面:从Activity中传输过来的数据为:' + msg,
120 | ToastAndroid.SHORT
121 | );
122 | },
123 | result => {
124 | ToastAndroid.show(
125 | 'JS界面:错误信息为:' + result,
126 | ToastAndroid.SHORT
127 | );
128 | }
129 | );
130 | }}
131 | >
132 | 调用原生 dataToJS 获取原生数据执行回调
133 |
134 | {
136 | NativeModules.MyIntentModule.show(
137 | 'Rn调用原生Toash方法及常量:' + NativeModules.MyIntentModule.OBJ,
138 | NativeModules.MyIntentModule.LONG
139 | );
140 | }}
141 | >
142 | 调用原生 show 方法及静态变量 TEST_OBJECT_KEY
143 |
144 | {
146 | try {
147 | var {
148 | relativeX,
149 | relativeY,
150 | width,
151 | height
152 | } = await NativeModules.MyIntentModule.dataToJSByPromise(10, 100);
153 | alert(relativeX + ':' + relativeY + ':' + width + ':' + height);
154 | } catch (e) {
155 | console.error(e);
156 | }
157 | }}
158 | >
159 | 调用原生 dataToJSByPromise 方法
160 |
161 |
162 | );
163 | }
164 | }
165 | var styles = StyleSheet.create({
166 | container: {
167 | flex: 1,
168 | borderWidth: 1,
169 | // borderColor: 'red',
170 | justifyContent: 'center'
171 | },
172 | hello: {
173 | fontSize: 20,
174 | textAlign: 'center',
175 | }
176 | });
177 |
178 | export default HelloWorld;
179 | // module.exports = HelloWorld;
180 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
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 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/RnView/MyRnViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo.RnView;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | //import android.support.design.widget.BottomNavigationView;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.widget.Toast;
12 | import android.widget.Button;
13 | import android.widget.TextView;
14 |
15 |
16 | import com.facebook.react.ReactActivity;
17 | import com.facebook.react.ReactActivityDelegate;
18 | import com.facebook.react.ReactPackage;
19 | import com.facebook.react.shell.MainReactPackage;
20 |
21 | import java.util.Arrays;
22 | import java.util.List;
23 | import java.util.concurrent.ArrayBlockingQueue;
24 |
25 | public class MyRnViewActivity extends ReactActivity {
26 | //构建一个阻塞的单一数据的队列
27 | public static ArrayBlockingQueue mQueue = new ArrayBlockingQueue(1);
28 |
29 | /**
30 | * Returns the name of the main component registered from JavaScript.
31 | * This is used to schedule rendering of the component.
32 | */
33 | @Override
34 | protected String getMainComponentName() {
35 | return "HelloWorld";
36 | }
37 |
38 | /**
39 | * 打开 带返回的Activity
40 | *
41 | * 通过 该 Activity_A 打开新的 Activity_B 后,在 Activity_B
42 | * 执行 this.setResult(Activity.RESULT_OK,new Intent().putExtra(key)); this.finish 关闭 Activity_B 并回传参数
43 | *
44 | * @param requestCode
45 | * @param resultCode
46 | * @param data
47 | */
48 | @Override
49 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
50 | super.onActivityResult(requestCode, resultCode, data);
51 | if (resultCode == RESULT_OK && requestCode == 200) {
52 | String result = data.getStringExtra("get_result");
53 | Toast.makeText(this, result, Toast.LENGTH_LONG);
54 | if (result != null && !result.equals("")) {
55 | mQueue.add(result);
56 | } else {
57 | mQueue.add("无数据啦");
58 | }
59 | } else {
60 | mQueue.add("没有回调...");
61 | }
62 | }
63 |
64 | @Override
65 | protected ReactActivityDelegate createReactActivityDelegate() {
66 | return new MyRnViewActivityDelegate(this, getMainComponentName());
67 | }
68 |
69 | //自定义MyRnViewActivityDelegate
70 | class MyRnViewActivityDelegate extends ReactActivityDelegate {
71 |
72 | public MyRnViewActivityDelegate(Activity activity, @javax.annotation.Nullable String mainComponentName) {
73 | super(activity, mainComponentName);
74 | }
75 |
76 | @javax.annotation.Nullable
77 | @Override
78 | protected Bundle getLaunchOptions() {
79 | Bundle bundle = new Bundle();
80 | bundle.putString("bundle", "android传递的初始化参数");
81 | return bundle;
82 | }
83 | }
84 |
85 | }
86 |
87 | //
88 | //public class MyRnViewActivity extends AppCompatActivity implements View.OnClickListener {
89 | //
90 | // private TextView mTextMessage;
91 | //
92 | // private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
93 | // = new BottomNavigationView.OnNavigationItemSelectedListener() {
94 | //
95 | // @Override
96 | // public boolean onNavigationItemSelected(@NonNull MenuItem item) {
97 | // switch (item.getItemId()) {
98 | // case R.id.navigation_home:
99 | // mTextMessage.setText(R.string.title_home);
100 | // return true;
101 | // case R.id.navigation_dashboard:
102 | // mTextMessage.setText(R.string.title_dashboard);
103 | // return true;
104 | // case R.id.navigation_notifications:
105 | // mTextMessage.setText(R.string.title_notifications);
106 | // return true;
107 | // }
108 | // return false;
109 | // }
110 | // };
111 | //
112 | // private Integer count = 0;
113 | //
114 | // @Override
115 | // public void onClick(View v) {
116 | // switch (v.getId()) {
117 | // case R.id.button:
118 | // count++;
119 | // Toast.makeText(MainActivity.this, "方式1 count:" + count, Toast.LENGTH_SHORT).show();
120 | // break;
121 | // case R.id.button2:
122 | // Toast.makeText(MainActivity.this, "方式2 count:" + count, Toast.LENGTH_SHORT).show();
123 | // Intent intent=new Intent(MainActivity.this, MyActivity.class);
124 | // startActivity(intent);
125 | // break;
126 | // default:
127 | // break;
128 | // }
129 | // }
130 | //
131 | // @Override
132 | // protected void onCreate(Bundle savedInstanceState) {
133 | // super.onCreate(savedInstanceState);
134 | // setContentView(R.layout.activity_main);
135 | //
136 | // mTextMessage = (TextView) findViewById(R.id.message);
137 | // BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
138 | // navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
139 | //
140 | // ((Button) findViewById(R.id.button)).setOnClickListener(this);
141 | // ((Button) findViewById(R.id.button2)).setOnClickListener(this);
142 | //
143 | //// Button button2 = (Button) findViewById(R.id.button2);
144 | //// button2.setOnClickListener(new View.OnClickListener() {
145 | //// @Override
146 | //// public void onClick(View v) {
147 | //// Toast.makeText(MainActivity.this, "方式二", Toast.LENGTH_SHORT)
148 | //// .show();
149 | //// }
150 | //// });
151 | //
152 | //// Button button3 = (Button) findViewById(R.id.button2);
153 | //// button3.setOnClickListener(new CustomButtonListener());
154 | // }
155 | //
156 | //// public class CustomButtonListener implements View.OnClickListener {
157 | ////
158 | //// @Override
159 | //// public void onClick(View v) {
160 | //// Toast.makeText(MainActivity.this, "方式三", Toast.LENGTH_SHORT).show();
161 | //// }
162 | ////
163 | //// }
164 | //
165 | //
166 | // public void onclick_button1(View view) {
167 | // Toast.makeText(this, "方式一", Toast.LENGTH_SHORT).show();
168 | // }
169 | //}
170 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/MyIntentModule.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.text.TextUtils;
6 | import android.util.Log;
7 | import android.widget.Toast;
8 |
9 | import com.example.cmacking.reactnativeandroiddemo.RnView.MyRnViewActivity;
10 | import com.example.cmacking.reactnativeandroiddemo.util.JSONHelper;
11 | import com.facebook.react.bridge.Arguments;
12 | import com.facebook.react.bridge.Callback;
13 | import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
14 | import com.facebook.react.bridge.Promise;
15 | import com.facebook.react.bridge.ReactApplicationContext;
16 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
17 | import com.facebook.react.bridge.ReactMethod;
18 | import com.facebook.react.bridge.WritableMap;
19 | import com.facebook.react.uimanager.IllegalViewOperationException;
20 | import com.facebook.react.uimanager.PixelUtil;
21 |
22 | import org.json.JSONException;
23 |
24 | import java.util.ArrayList;
25 | import java.util.HashMap;
26 | import java.util.List;
27 | import java.util.Map;
28 |
29 | /**
30 | * 原生Activity与React交互——模块
31 | */
32 |
33 | public class MyIntentModule extends ReactContextBaseJavaModule {
34 |
35 | public MyIntentModule(ReactApplicationContext reactContext) {
36 | super(reactContext);
37 | }
38 |
39 | @Override
40 | public String getName() {
41 | return "MyIntentModule";
42 | }
43 | //注意:记住getName方法中的命名名称,JS中调用需要
44 |
45 | @ReactMethod
46 | public void startActivityFromJS(String name, String params) {
47 | try {
48 | Activity currentActivity = getCurrentActivity();
49 | if (null != currentActivity) {
50 | Log.i("info", params);
51 | Class toActivity = Class.forName(name);
52 | Intent intent = new Intent(currentActivity, toActivity);
53 | Toast.makeText(currentActivity, "Android.MyIntentModule.startActivityFromJS.params 这是由RN传递过来的参数:Key params => " + params, Toast.LENGTH_SHORT).show();
54 | intent.putExtra("params", params);
55 | currentActivity.startActivity(intent);
56 | }
57 | } catch (Exception e) {
58 | throw new JSApplicationIllegalArgumentException(
59 | "不能打开Activity : " + e.getMessage());
60 | }
61 | }
62 |
63 | @ReactMethod
64 | public void startActivityFromJSGetResult(String className, int requestCode, Callback successBack, Callback errorBack) {
65 | try {
66 | Activity currentActivity = getCurrentActivity();
67 | if (currentActivity != null) {
68 | Class toActivity = Class.forName(className);
69 | Intent intent = new Intent(currentActivity, toActivity);
70 | currentActivity.startActivityForResult(intent, requestCode);
71 | //进行回调数据
72 | successBack.invoke(MyRnViewActivity.mQueue.take());
73 | }
74 | } catch (Exception e) {
75 | errorBack.invoke(e.getMessage());
76 | e.printStackTrace();
77 | }
78 |
79 | }
80 |
81 | @ReactMethod
82 | public void dataToJS(Callback successBack, Callback errorBack) {
83 | try {
84 | Activity currentActivity = getCurrentActivity();
85 | String result = currentActivity.getIntent().getStringExtra("params");
86 | if (TextUtils.isEmpty(result)) {
87 | result = "没有数据";
88 | }
89 | try {
90 | Thread.sleep(2000);
91 | } catch (InterruptedException e) {
92 | e.printStackTrace();
93 | }
94 | successBack.invoke(result);
95 | } catch (Exception e) {
96 | errorBack.invoke(e.getMessage());
97 | }
98 | }
99 |
100 | @ReactMethod
101 | public void dataToJSByPromise(
102 | int tag,
103 | int ancestorTag,
104 | Promise promise) {
105 | try {
106 |
107 | WritableMap map = Arguments.createMap();
108 |
109 | map.putDouble("relativeX", tag + 96);
110 | map.putDouble("relativeY", tag + 97);
111 | map.putDouble("width", ancestorTag + 98);
112 | map.putDouble("height", ancestorTag + 99);
113 | Thread.sleep(2000);
114 | promise.resolve(map);
115 | } catch (IllegalViewOperationException e) {
116 | promise.reject(e);
117 | } catch (InterruptedException e) {
118 | e.printStackTrace();
119 | }
120 | }
121 |
122 |
123 | private static final String DURAION_SHORT_KEY = "SHORT";
124 | private static final String DURAION_LONG_KEY = "LONG";
125 | private static final String TEST_OBJECT_KEY = "OBJ";
126 |
127 | @Override
128 | public Map getConstants() {
129 | final Map constants = new HashMap<>();
130 | constants.put(DURAION_SHORT_KEY, Toast.LENGTH_SHORT);
131 | constants.put(DURAION_LONG_KEY, Toast.LENGTH_LONG);
132 | String str = null;
133 | try {
134 | str = GetUesrByStr();
135 | } catch (JSONException e) {
136 | e.printStackTrace();
137 | }
138 | constants.put(TEST_OBJECT_KEY, str);
139 | return constants;
140 | }
141 |
142 | public String GetUesrByStr() throws JSONException {
143 | User user = new User();
144 | user.setName("abcd");
145 | user.setPassword("123456");
146 |
147 | User user1 = new User();
148 | user1.setName("abcdf");
149 | user1.setPassword("1234567");
150 |
151 | String jsonStrUser = JSONHelper.toJSON(user); //序列化
152 | // User jsonUser = JSONHelper.parseObject(jsonStrUser, User.class); //反序列化
153 | // Map mapUser = JSONHelper.parseObject(jsonStrUser, HashMap.class); //反序列化
154 |
155 |
156 | List sourceList = new ArrayList();
157 | sourceList.add(user);
158 | sourceList.add(user1);
159 | String jsonStrUserList = JSONHelper.toJSON(sourceList); //序列化
160 | // List listUser = (List) JSONHelper.parseCollection(jsonStrUserList, List.class, User.class); //反序列化
161 |
162 | return jsonStrUserList;
163 | }
164 |
165 | // Boolean -> Bool
166 | // Integer -> Number
167 | // Double -> Number
168 | // Float -> Number
169 | // String -> String
170 | // Callback -> function
171 | // ReadableMap -> Object
172 | // ReadableArray -> Array
173 | @ReactMethod
174 | public void show(String message, int duration) {
175 | Toast.makeText(getReactApplicationContext(), message, duration).show();
176 | }
177 |
178 | //注意:startActivityFromJS、dataToJS方法添加RN注解(@ReactMethod),否则该方法将不被添加到RN中
179 | }
180 |
181 | class User {
182 | private String name;
183 | private String password;
184 |
185 | public String getName() {
186 | return name;
187 | }
188 |
189 | public void setName(String name) {
190 | this.name = name;
191 | }
192 |
193 | public String getPassword() {
194 | return password;
195 | }
196 |
197 | public void setPassword(String password) {
198 | this.password = password;
199 | }
200 | }
201 |
202 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/cmacking/reactnativeandroiddemo/util/JSONHelper.java:
--------------------------------------------------------------------------------
1 | package com.example.cmacking.reactnativeandroiddemo.util;
2 |
3 | import java.lang.reflect.Array;
4 | import java.lang.reflect.Field;
5 | import java.lang.reflect.Method;
6 | import java.lang.reflect.ParameterizedType;
7 | import java.lang.reflect.Type;
8 | import java.text.SimpleDateFormat;
9 | import java.util.ArrayList;
10 | import java.util.Collection;
11 | import java.util.Date;
12 | import java.util.HashMap;
13 | import java.util.HashSet;
14 | import java.util.Iterator;
15 | import java.util.List;
16 | import java.util.Locale;
17 | import java.util.Map;
18 | import java.util.Set;
19 |
20 | import org.json.JSONArray;
21 | import org.json.JSONException;
22 | import org.json.JSONObject;
23 | import org.json.JSONStringer;
24 |
25 | import android.util.Log;
26 |
27 |
28 | /**
29 | * @author keane
30 | */
31 | public class JSONHelper {
32 | private static String TAG = "JSONHelper";
33 |
34 | /**
35 | * 将对象转换成Json字符串
36 | *
37 | * @param obj
38 | * @return json类型字符串
39 | */
40 | public static String toJSON(Object obj) {
41 | JSONStringer js = new JSONStringer();
42 | serialize(js, obj);
43 | return js.toString();
44 | }
45 |
46 | /**
47 | * 序列化为JSON
48 | *
49 | * @param js json对象
50 | * @param o 待需序列化的对象
51 | */
52 | private static void serialize(JSONStringer js, Object o) {
53 | if (isNull(o)) {
54 | try {
55 | js.value(null);
56 | } catch (JSONException e) {
57 | e.printStackTrace();
58 | }
59 | return;
60 | }
61 |
62 | Class> clazz = o.getClass();
63 | if (isObject(clazz)) { // 对象
64 | serializeObject(js, o);
65 | } else if (isArray(clazz)) { // 数组
66 | serializeArray(js, o);
67 | } else if (isCollection(clazz)) { // 集合
68 | Collection> collection = (Collection>) o;
69 | serializeCollect(js, collection);
70 | } else if (isMap(clazz)) { // 集合
71 | HashMap, ?> collection = (HashMap, ?>) o;
72 | serializeMap(js, collection);
73 | } else { // 单个值
74 | try {
75 | js.value(o);
76 | } catch (JSONException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * 序列化数组
84 | *
85 | * @param js json对象
86 | * @param array 数组
87 | */
88 | private static void serializeArray(JSONStringer js, Object array) {
89 | try {
90 | js.array();
91 | for (int i = 0; i < Array.getLength(array); ++i) {
92 | Object o = Array.get(array, i);
93 | serialize(js, o);
94 | }
95 | js.endArray();
96 | } catch (Exception e) {
97 | e.printStackTrace();
98 | }
99 | }
100 |
101 | /**
102 | * 序列化集合
103 | *
104 | * @param js json对象
105 | * @param collection 集合
106 | */
107 | private static void serializeCollect(JSONStringer js, Collection> collection) {
108 | try {
109 | js.array();
110 | for (Object o : collection) {
111 | serialize(js, o);
112 | }
113 | js.endArray();
114 | } catch (Exception e) {
115 | e.printStackTrace();
116 | }
117 | }
118 |
119 | /**
120 | * 序列化Map
121 | *
122 | * @param js json对象
123 | * @param map map对象
124 | */
125 | private static void serializeMap(JSONStringer js, Map, ?> map) {
126 | try {
127 | js.object();
128 | @SuppressWarnings("unchecked")
129 | Map valueMap = (Map) map;
130 | Iterator> it = valueMap.entrySet().iterator();
131 | while (it.hasNext()) {
132 | Map.Entry entry = (Map.Entry) it.next();
133 | js.key(entry.getKey());
134 | serialize(js, entry.getValue());
135 | }
136 | js.endObject();
137 | } catch (Exception e) {
138 | e.printStackTrace();
139 | }
140 | }
141 |
142 | /**
143 | * 序列化对象
144 | *
145 | * @param js json对象
146 | * @param obj 待序列化对象
147 | */
148 | private static void serializeObject(JSONStringer js, Object obj) {
149 | try {
150 | js.object();
151 | Class extends Object> objClazz = obj.getClass();
152 | Method[] methods = objClazz.getDeclaredMethods();
153 | Field[] fields = objClazz.getDeclaredFields();
154 | for (Field field : fields) {
155 | try {
156 | String fieldType = field.getType().getSimpleName();
157 | String fieldGetName = parseMethodName(field.getName(), "get");
158 | if (!haveMethod(methods, fieldGetName)) {
159 | continue;
160 | }
161 | Method fieldGetMet = objClazz.getMethod(fieldGetName, new Class[]{});
162 | Object fieldVal = fieldGetMet.invoke(obj, new Object[]{});
163 | String result = null;
164 | if ("Date".equals(fieldType)) {
165 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
166 | result = sdf.format((Date) fieldVal);
167 |
168 | } else {
169 | if (null != fieldVal) {
170 | result = String.valueOf(fieldVal);
171 | }
172 | }
173 | js.key(field.getName());
174 | serialize(js, result);
175 | } catch (Exception e) {
176 | continue;
177 | }
178 | }
179 | js.endObject();
180 | } catch (Exception e) {
181 | e.printStackTrace();
182 | }
183 | }
184 |
185 | /**
186 | * 判断是否存在某属性的 get方法
187 | *
188 | * @param methods 引用方法的数组
189 | * @param fieldMethod 方法名称
190 | * @return true或者false
191 | */
192 | public static boolean haveMethod(Method[] methods, String fieldMethod) {
193 | for (Method met : methods) {
194 | if (fieldMethod.equals(met.getName())) {
195 | return true;
196 | }
197 | }
198 | return false;
199 | }
200 |
201 | /**
202 | * 拼接某属性的 get或者set方法
203 | *
204 | * @param fieldName 字段名称
205 | * @param methodType 方法类型
206 | * @return 方法名称
207 | */
208 | public static String parseMethodName(String fieldName, String methodType) {
209 | if (null == fieldName || "".equals(fieldName)) {
210 | return null;
211 | }
212 | return methodType + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
213 | }
214 |
215 | /**
216 | * 给字段赋值
217 | *
218 | * @param obj 实例对象
219 | * @param valMap 值集合
220 | */
221 | public static void setFieldValue(Object obj, Map valMap) {
222 | Class> cls = obj.getClass();
223 | // 取出bean里的所有方法
224 | Method[] methods = cls.getDeclaredMethods();
225 | Field[] fields = cls.getDeclaredFields();
226 |
227 | for (Field field : fields) {
228 | try {
229 | String setMetodName = parseMethodName(field.getName(), "set");
230 | if (!haveMethod(methods, setMetodName)) {
231 | continue;
232 | }
233 | Method fieldMethod = cls.getMethod(setMetodName, field
234 | .getType());
235 | String value = valMap.get(field.getName());
236 | if (null != value && !"".equals(value)) {
237 | String fieldType = field.getType().getSimpleName();
238 | if ("String".equals(fieldType)) {
239 | fieldMethod.invoke(obj, value);
240 | } else if ("Date".equals(fieldType)) {
241 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
242 | Date temp = sdf.parse(value);
243 | fieldMethod.invoke(obj, temp);
244 | } else if ("Integer".equals(fieldType)
245 | || "int".equals(fieldType)) {
246 | Integer intval = Integer.parseInt(value);
247 | fieldMethod.invoke(obj, intval);
248 | } else if ("Long".equalsIgnoreCase(fieldType)) {
249 | Long temp = Long.parseLong(value);
250 | fieldMethod.invoke(obj, temp);
251 | } else if ("Double".equalsIgnoreCase(fieldType)) {
252 | Double temp = Double.parseDouble(value);
253 | fieldMethod.invoke(obj, temp);
254 | } else if ("Boolean".equalsIgnoreCase(fieldType)) {
255 | Boolean temp = Boolean.parseBoolean(value);
256 | fieldMethod.invoke(obj, temp);
257 | } else {
258 | System.out.println("setFieldValue not supper type:" + fieldType);
259 | }
260 | }
261 | } catch (Exception e) {
262 | continue;
263 | }
264 | }
265 |
266 | }
267 |
268 | /**
269 | * bean对象转Map
270 | *
271 | * @param obj 实例对象
272 | * @return map集合
273 | */
274 | public static Map beanToMap(Object obj) {
275 | Class> cls = obj.getClass();
276 | Map valueMap = new HashMap();
277 | // 取出bean里的所有方法
278 | Method[] methods = cls.getDeclaredMethods();
279 | Field[] fields = cls.getDeclaredFields();
280 | for (Field field : fields) {
281 | try {
282 | String fieldType = field.getType().getSimpleName();
283 | String fieldGetName = parseMethodName(field.getName(), "get");
284 | if (!haveMethod(methods, fieldGetName)) {
285 | continue;
286 | }
287 | Method fieldGetMet = cls.getMethod(fieldGetName, new Class[]{});
288 | Object fieldVal = fieldGetMet.invoke(obj, new Object[]{});
289 | String result = null;
290 | if ("Date".equals(fieldType)) {
291 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
292 | result = sdf.format((Date) fieldVal);
293 |
294 | } else {
295 | if (null != fieldVal) {
296 | result = String.valueOf(fieldVal);
297 | }
298 | }
299 | valueMap.put(field.getName(), result);
300 | } catch (Exception e) {
301 | continue;
302 | }
303 | }
304 | return valueMap;
305 |
306 | }
307 |
308 | /**
309 | * 给对象的字段赋值
310 | *
311 | * @param obj 类实例
312 | * @param fieldSetMethod 字段方法
313 | * @param fieldType 字段类型
314 | * @param value
315 | */
316 | public static void setFiedlValue(Object obj, Method fieldSetMethod, String fieldType, Object value) {
317 |
318 | try {
319 | if (null != value && !"".equals(value)) {
320 | if ("String".equals(fieldType)) {
321 | fieldSetMethod.invoke(obj, value.toString());
322 | } else if ("Date".equals(fieldType)) {
323 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
324 | Date temp = sdf.parse(value.toString());
325 | fieldSetMethod.invoke(obj, temp);
326 | } else if ("Integer".equals(fieldType)
327 | || "int".equals(fieldType)) {
328 | Integer intval = Integer.parseInt(value.toString());
329 | fieldSetMethod.invoke(obj, intval);
330 | } else if ("Long".equalsIgnoreCase(fieldType)) {
331 | Long temp = Long.parseLong(value.toString());
332 | fieldSetMethod.invoke(obj, temp);
333 | } else if ("Double".equalsIgnoreCase(fieldType)) {
334 | Double temp = Double.parseDouble(value.toString());
335 | fieldSetMethod.invoke(obj, temp);
336 | } else if ("Boolean".equalsIgnoreCase(fieldType)) {
337 | Boolean temp = Boolean.parseBoolean(value.toString());
338 | fieldSetMethod.invoke(obj, temp);
339 | } else {
340 | fieldSetMethod.invoke(obj, value);
341 | Log.e(TAG, TAG + ">>>>setFiedlValue -> not supper type" + fieldType);
342 | }
343 | }
344 |
345 | } catch (Exception e) {
346 | // Log.e(TAG, TAG + ">>>>>>>>>>set value error.",e);
347 | e.printStackTrace();
348 | }
349 |
350 | }
351 |
352 | /**
353 | * 反序列化简单对象
354 | *
355 | * @param jo json对象
356 | * @param clazz 实体类类型
357 | * @return 反序列化后的实例
358 | * @throws JSONException
359 | */
360 | public static T parseObject(JSONObject jo, Class clazz) throws JSONException {
361 | if (clazz == null || isNull(jo)) {
362 | return null;
363 | }
364 |
365 | T obj = newInstance(clazz);
366 | if (obj == null) {
367 | return null;
368 | }
369 | if (isMap(clazz)) {
370 | setField(obj, jo);
371 | } else {
372 | // 取出bean里的所有方法
373 | Method[] methods = clazz.getDeclaredMethods();
374 | Field[] fields = clazz.getDeclaredFields();
375 | for (Field f : fields) {
376 | String setMetodName = parseMethodName(f.getName(), "set");
377 | if (!haveMethod(methods, setMetodName)) {
378 | continue;
379 | }
380 | try {
381 | Method fieldMethod = clazz.getMethod(setMetodName, f.getType());
382 | setField(obj, fieldMethod, f, jo);
383 | } catch (Exception e) {
384 | e.printStackTrace();
385 | }
386 | }
387 | }
388 | return obj;
389 | }
390 |
391 | /**
392 | * 反序列化简单对象
393 | *
394 | * @param jsonStr json字符串
395 | * @param clazz 实体类类型
396 | * @return 反序列化后的实例
397 | * @throws JSONException
398 | */
399 | public static T parseObject(String jsonStr, Class clazz) throws JSONException {
400 | if (clazz == null || jsonStr == null || jsonStr.length() == 0) {
401 | return null;
402 | }
403 |
404 | JSONObject jo = null;
405 | jo = new JSONObject(jsonStr);
406 | if (isNull(jo)) {
407 | return null;
408 | }
409 |
410 | return parseObject(jo, clazz);
411 | }
412 |
413 | /**
414 | * 反序列化数组对象
415 | *
416 | * @param ja json数组
417 | * @param clazz 实体类类型
418 | * @return 反序列化后的数组
419 | */
420 | public static T[] parseArray(JSONArray ja, Class clazz) {
421 | if (clazz == null || isNull(ja)) {
422 | return null;
423 | }
424 |
425 | int len = ja.length();
426 |
427 | @SuppressWarnings("unchecked")
428 | T[] array = (T[]) Array.newInstance(clazz, len);
429 |
430 | for (int i = 0; i < len; ++i) {
431 | try {
432 | JSONObject jo = ja.getJSONObject(i);
433 | T o = parseObject(jo, clazz);
434 | array[i] = o;
435 | } catch (JSONException e) {
436 | e.printStackTrace();
437 | }
438 | }
439 |
440 | return array;
441 | }
442 |
443 |
444 | /**
445 | * 反序列化数组对象
446 | *
447 | * @param jsonStr json字符串
448 | * @param clazz 实体类类型
449 | * @return 序列化后的数组
450 | */
451 | public static T[] parseArray(String jsonStr, Class clazz) {
452 | if (clazz == null || jsonStr == null || jsonStr.length() == 0) {
453 | return null;
454 | }
455 | JSONArray jo = null;
456 | try {
457 | jo = new JSONArray(jsonStr);
458 | } catch (JSONException e) {
459 | e.printStackTrace();
460 | }
461 |
462 | if (isNull(jo)) {
463 | return null;
464 | }
465 |
466 | return parseArray(jo, clazz);
467 | }
468 |
469 | /**
470 | * 反序列化泛型集合
471 | *
472 | * @param ja json数组
473 | * @param collectionClazz 集合类型
474 | * @param genericType 实体类类型
475 | * @return
476 | * @throws JSONException
477 | */
478 | @SuppressWarnings("unchecked")
479 | public static Collection parseCollection(JSONArray ja, Class> collectionClazz,
480 | Class genericType) throws JSONException {
481 |
482 | if (collectionClazz == null || genericType == null || isNull(ja)) {
483 | return null;
484 | }
485 |
486 | Collection collection = (Collection) newInstance(collectionClazz);
487 |
488 | for (int i = 0; i < ja.length(); ++i) {
489 | try {
490 | JSONObject jo = ja.getJSONObject(i);
491 | T o = parseObject(jo, genericType);
492 | collection.add(o);
493 | } catch (JSONException e) {
494 | e.printStackTrace();
495 | }
496 | }
497 |
498 | return collection;
499 | }
500 |
501 | /**
502 | * 反序列化泛型集合
503 | *
504 | * @param jsonStr json字符串
505 | * @param collectionClazz 集合类型
506 | * @param genericType 实体类类型
507 | * @return 反序列化后的数组
508 | * @throws JSONException
509 | */
510 | public static Collection parseCollection(String jsonStr, Class> collectionClazz,
511 | Class genericType) throws JSONException {
512 | if (collectionClazz == null || genericType == null || jsonStr == null
513 | || jsonStr.length() == 0) {
514 | return null;
515 | }
516 | JSONArray jo = null;
517 | try {
518 | //如果为数组,则此处转化时,需要去掉前面的键,直接后面的[]中的值
519 | int index = jsonStr.indexOf("[");
520 | String arrayString = null;
521 |
522 | //获取数组的字符串
523 | if (-1 != index) {
524 | arrayString = jsonStr.substring(index);
525 | }
526 |
527 | //如果为数组,使用数组转化
528 | if (null != arrayString) {
529 | jo = new JSONArray(arrayString);
530 | } else {
531 | jo = new JSONArray(jsonStr);
532 | }
533 |
534 | } catch (JSONException e) {
535 | e.printStackTrace();
536 | }
537 |
538 | if (isNull(jo)) {
539 | return null;
540 | }
541 |
542 | return parseCollection(jo, collectionClazz, genericType);
543 | }
544 |
545 | /**
546 | * 根据类型创建对象
547 | *
548 | * @param clazz 待创建实例的类型
549 | * @return 实例对象
550 | * @throws JSONException
551 | */
552 | @SuppressWarnings({"unchecked", "rawtypes"})
553 | private static T newInstance(Class clazz) throws JSONException {
554 | if (clazz == null)
555 | return null;
556 | T obj = null;
557 | if (clazz.isInterface()) {
558 | if (clazz.equals(Map.class)) {
559 | obj = (T) new HashMap();
560 | } else if (clazz.equals(List.class)) {
561 | obj = (T) new ArrayList();
562 | } else if (clazz.equals(Set.class)) {
563 | obj = (T) new HashSet();
564 | } else {
565 | throw new JSONException("unknown interface: " + clazz);
566 | }
567 | } else {
568 | try {
569 | obj = clazz.newInstance();
570 | } catch (Exception e) {
571 | throw new JSONException("unknown class type: " + clazz);
572 | }
573 | }
574 | return obj;
575 | }
576 |
577 | /**
578 | * 设定Map的值
579 | *
580 | * @param obj 待赋值字段的对象
581 | * @param jo json实例
582 | */
583 | private static void setField(Object obj, JSONObject jo) {
584 | try {
585 | @SuppressWarnings("unchecked")
586 | Iterator keyIter = jo.keys();
587 | String key;
588 | Object value;
589 | @SuppressWarnings("unchecked")
590 | Map valueMap = (Map) obj;
591 | while (keyIter.hasNext()) {
592 | key = (String) keyIter.next();
593 | value = jo.get(key);
594 | valueMap.put(key, value);
595 |
596 | }
597 | } catch (JSONException e) {
598 | e.printStackTrace();
599 | }
600 | }
601 |
602 | /**
603 | * 设定字段的值
604 | *
605 | * @param obj 待赋值字段的对象
606 | * @param fieldSetMethod 字段方法名
607 | * @param field 字段
608 | * @param jo json实例
609 | */
610 | private static void setField(Object obj, Method fieldSetMethod, Field field, JSONObject jo) {
611 | String name = field.getName();
612 | Class> clazz = field.getType();
613 | try {
614 | if (isArray(clazz)) { // 数组
615 | Class> c = clazz.getComponentType();
616 | JSONArray ja = jo.optJSONArray(name);
617 | if (!isNull(ja)) {
618 | Object array = parseArray(ja, c);
619 | setFiedlValue(obj, fieldSetMethod, clazz.getSimpleName(), array);
620 | }
621 | } else if (isCollection(clazz)) { // 泛型集合
622 | // 获取定义的泛型类型
623 | Class> c = null;
624 | Type gType = field.getGenericType();
625 | if (gType instanceof ParameterizedType) {
626 | ParameterizedType ptype = (ParameterizedType) gType;
627 | Type[] targs = ptype.getActualTypeArguments();
628 | if (targs != null && targs.length > 0) {
629 | Type t = targs[0];
630 | c = (Class>) t;
631 | }
632 | }
633 |
634 | JSONArray ja = jo.optJSONArray(name);
635 | if (!isNull(ja)) {
636 | Object o = parseCollection(ja, clazz, c);
637 | setFiedlValue(obj, fieldSetMethod, clazz.getSimpleName(), o);
638 | }
639 | } else if (isSingle(clazz)) { // 值类型
640 | Object o = jo.opt(name);
641 | if (o != null) {
642 | setFiedlValue(obj, fieldSetMethod, clazz.getSimpleName(), o);
643 | }
644 | } else if (isObject(clazz)) { // 对象
645 | JSONObject j = jo.optJSONObject(name);
646 | if (!isNull(j)) {
647 | Object o = parseObject(j, clazz);
648 | setFiedlValue(obj, fieldSetMethod, clazz.getSimpleName(), o);
649 | }
650 | } else if (isList(clazz)) { // 列表
651 | // JSONObject j = jo.optJSONObject(name);
652 | // if (!isNull(j)) {
653 | // Object o = parseObject(j, clazz);
654 | // f.set(obj, o);
655 | // }
656 | } else {
657 | throw new Exception("unknow type!");
658 | }
659 | } catch (Exception e) {
660 | e.printStackTrace();
661 | }
662 | }
663 |
664 | /**
665 | * 设定字段的值
666 | *
667 | * @param obj 待赋值字段的对象
668 | * @param field 字段
669 | * @param jo json实例
670 | */
671 | @SuppressWarnings("unused")
672 | private static void setField(Object obj, Field field, JSONObject jo) {
673 | String name = field.getName();
674 | Class> clazz = field.getType();
675 | try {
676 | if (isArray(clazz)) { // 数组
677 | Class> c = clazz.getComponentType();
678 | JSONArray ja = jo.optJSONArray(name);
679 | if (!isNull(ja)) {
680 | Object array = parseArray(ja, c);
681 | field.set(obj, array);
682 | }
683 | } else if (isCollection(clazz)) { // 泛型集合
684 | // 获取定义的泛型类型
685 | Class> c = null;
686 | Type gType = field.getGenericType();
687 | if (gType instanceof ParameterizedType) {
688 | ParameterizedType ptype = (ParameterizedType) gType;
689 | Type[] targs = ptype.getActualTypeArguments();
690 | if (targs != null && targs.length > 0) {
691 | Type t = targs[0];
692 | c = (Class>) t;
693 | }
694 | }
695 | JSONArray ja = jo.optJSONArray(name);
696 | if (!isNull(ja)) {
697 | Object o = parseCollection(ja, clazz, c);
698 | field.set(obj, o);
699 | }
700 | } else if (isSingle(clazz)) { // 值类型
701 | Object o = jo.opt(name);
702 | if (o != null) {
703 | field.set(obj, o);
704 | }
705 | } else if (isObject(clazz)) { // 对象
706 | JSONObject j = jo.optJSONObject(name);
707 | if (!isNull(j)) {
708 | Object o = parseObject(j, clazz);
709 | field.set(obj, o);
710 | }
711 | } else if (isList(clazz)) { // 列表
712 | JSONObject j = jo.optJSONObject(name);
713 | if (!isNull(j)) {
714 | Object o = parseObject(j, clazz);
715 | field.set(obj, o);
716 | }
717 | } else {
718 | throw new Exception("unknow type!");
719 | }
720 | } catch (Exception e) {
721 | e.printStackTrace();
722 | }
723 | }
724 |
725 | /**
726 | * 判断对象是否为空
727 | *
728 | * @param obj 实例
729 | * @return
730 | */
731 | private static boolean isNull(Object obj) {
732 | if (obj instanceof JSONObject) {
733 | return JSONObject.NULL.equals(obj);
734 | }
735 | return obj == null;
736 | }
737 |
738 | /**
739 | * 判断是否是值类型
740 | *
741 | * @param clazz
742 | * @return
743 | */
744 | private static boolean isSingle(Class> clazz) {
745 | return isBoolean(clazz) || isNumber(clazz) || isString(clazz);
746 | }
747 |
748 | /**
749 | * 是否布尔值
750 | *
751 | * @param clazz
752 | * @return
753 | */
754 | public static boolean isBoolean(Class> clazz) {
755 | return (clazz != null)
756 | && ((Boolean.TYPE.isAssignableFrom(clazz)) || (Boolean.class
757 | .isAssignableFrom(clazz)));
758 | }
759 |
760 | /**
761 | * 是否数值
762 | *
763 | * @param clazz
764 | * @return
765 | */
766 | public static boolean isNumber(Class> clazz) {
767 | return (clazz != null)
768 | && ((Byte.TYPE.isAssignableFrom(clazz)) || (Short.TYPE.isAssignableFrom(clazz))
769 | || (Integer.TYPE.isAssignableFrom(clazz))
770 | || (Long.TYPE.isAssignableFrom(clazz))
771 | || (Float.TYPE.isAssignableFrom(clazz))
772 | || (Double.TYPE.isAssignableFrom(clazz)) || (Number.class
773 | .isAssignableFrom(clazz)));
774 | }
775 |
776 | /**
777 | * 判断是否是字符串
778 | *
779 | * @param clazz
780 | * @return
781 | */
782 | public static boolean isString(Class> clazz) {
783 | return (clazz != null)
784 | && ((String.class.isAssignableFrom(clazz))
785 | || (Character.TYPE.isAssignableFrom(clazz)) || (Character.class
786 | .isAssignableFrom(clazz)));
787 | }
788 |
789 | /**
790 | * 判断是否是对象
791 | *
792 | * @param clazz
793 | * @return
794 | */
795 | private static boolean isObject(Class> clazz) {
796 | return clazz != null && !isSingle(clazz) && !isArray(clazz) && !isCollection(clazz) && !isMap(clazz);
797 | }
798 |
799 | /**
800 | * 判断是否是数组
801 | *
802 | * @param clazz
803 | * @return
804 | */
805 | public static boolean isArray(Class> clazz) {
806 | return clazz != null && clazz.isArray();
807 | }
808 |
809 | /**
810 | * 判断是否是集合
811 | *
812 | * @param clazz
813 | * @return
814 | */
815 | public static boolean isCollection(Class> clazz) {
816 | return clazz != null && Collection.class.isAssignableFrom(clazz);
817 | }
818 |
819 | /**
820 | * 判断是否是Map
821 | *
822 | * @param clazz
823 | * @return
824 | */
825 | public static boolean isMap(Class> clazz) {
826 | return clazz != null && Map.class.isAssignableFrom(clazz);
827 | }
828 |
829 | /**
830 | * 判断是否是列表
831 | *
832 | * @param clazz
833 | * @return
834 | */
835 | public static boolean isList(Class> clazz) {
836 | return clazz != null && List.class.isAssignableFrom(clazz);
837 | }
838 |
839 | }
--------------------------------------------------------------------------------