React Native网络请求学习笔记(Android版本)
来源:互联网 发布:html5编程软件 编辑:程序博客网 时间:2024/06/06 03:00
- 概述
- 基本示例
- 效果
- 代码
- 注意事项
- 实现原理
- 原理概述
- 初始化
- 初始化java层
- 初始化c层
- 初始化小结
- 网络请求
- 网络请求js层
- 网络请求c层
- 网络请求java层
- 网络返回java层
- 网络返回c层
- 网络返回js层
- 代码下载
- 参考资料
概述
这篇文章首先会展示react native的一个简单的访问网络请求的例子。然后会分析代码的实现。
注:
1.本文示例及代码分析基于react native 0.40版本。
2.限于水平有限,c++代码部分分析比较简单。期望更正,谢谢。
基本示例
注:示例来自http://blog.csdn.net/qq_16086969/article/details/53522980,并做了一些修改。
效果
- 页面初始化的时候展示一个可点击的文本“点我测试网络”。
- 用户点击文本后,会访问网络和风天气api
- 网络请求完成后 ,更新UI,具体如下:
代码
render() { return ( <View style={styles.container}> <ActivityIndicator animating={this.state.isLoading} /> <Text style={styles.welcome} onPress={this.requestNowWeatherFromServer.bind(this)}> 点我测试网络 </Text> <Text style={styles.instructions}> {this.state.resultJson} </Text> </View> ); }
可以看到用户点击“点我测试网络”,会调用this.requestNowWeatherFromServer.bind(this)方法
requestNowWeatherFromServer(){ if(this.state.isLoading==true){ return; } this.setState({ resultJson:null, isLoading:true }); try { NetworkService.requestNowWeatherFromServer() .then((response) => { let data = response; this.setState({ resultJson:data==null?null:JSON.stringify(data), isLoading:false }); console.log("返回数据:"+JSON.stringify(data)); }) } catch(e) { alert(e); this.setState({ isLoading:false }); } }
首先,如果isLoading为true,直接返回(防止重复点击)。然后,调用NetworkService.requestNowWeatherFromServer请求网络。最后将网络请求的返回值赋值给resultJson。
import NetworkService from './network.api.js';
NetworkService是network.api.js这个文件中定义的,具体如下:
//和风天气const baseURL = "https://free-api.heweather.com/v5/";function requestFromServer(...props) { this.url = props.shift(1); this.options = props.shift(1); return fetch(this.url, Object.assign({}, this.options)) .then((response) => { return response.json() });}export default { //http://docs.heweather.com/224326 requestNowWeatherFromServer() { var subURL = "now?city=beijing&key=9e6aa5cbcb994295ae8e54da94f48bba"; return requestFromServer(`${baseURL}/${subURL}`, { method: 'get', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }); }};
可以看到requestNowWeatherFromServer方法调用了requestFromServer方法,最终调用了react native提供的fetch方法。
fetch方法返回了response.json()给调用端,最终赋值给了state.resultJson:
<Text style={styles.instructions}> {this.state.resultJson} </Text>
state.resultJson是Text使用的,这样就将网络请求的结果展示出来。
注意事项
-1.fetch方法支持get、post,支持header。post示例如下
fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: 'firstValue', secondParam: 'secondValue', })})
-2.底层实现默认不支持https,需要修改代码
修改MainApplication
@Override public void onCreate() { super.onCreate(); OkHttpClientProvider.replaceOkHttpClient(HttpsOkHttpClient.initCustomOkHttpClient());//为了支持https,替换默认的okhttpClient SoLoader.init(this, /* native exopackage */ false); }
调用OkHttpClientProvider.replaceOkHttpClient替换为自己的OkHttpClient。
OkHttpClient通过HttpsOkHttpClient.initCustomOkHttpClient()构建并返回
public class HttpsOkHttpClient { /** * react native默认不支持https请求,这里提供支持https的OKHttpClient * @return */ public static OkHttpClient initCustomOkHttpClient(){ OkHttpClient.Builder client = new OkHttpClient.Builder() .connectTimeout(0, TimeUnit.MILLISECONDS) .readTimeout(0, TimeUnit.MILLISECONDS) .writeTimeout(0, TimeUnit.MILLISECONDS) .cookieJar(new ReactCookieJarContainer()); OkHttpClient.Builder builder = OkHttpClientProvider.enableTls12OnPreLollipop(client); builder.sslSocketFactory(getSSLSocketFactory()) .hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; //忽略所有的认证,直接返回了true } }); return builder.build(); } private static SSLSocketFactory getSSLSocketFactory() { TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}; SSLSocketFactory sslSocketFactory = null; try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init((KeyManager[])null, trustAllCerts, new SecureRandom()); sslSocketFactory = sslContext.getSocketFactory(); } catch (Exception e) { e.printStackTrace(); } return sslSocketFactory; }}
实现原理
原理概述
图片来自http://blog.csdn.net/megatronkings/article/details/51114278
如上图,react native在android设备上最终使用的的原生的UI控件:包括UI、网络请求等。而react native完全是用js来开发。js代码就是通过C++代码同java端进行双向映射的。类似与普通android开发中的webview控件与js交互的过程,react native使用了自己的webkit内核。
初始化
初始化java层
react-native自动生成的android代码有MainApplication和MainActivity
public class MainApplication extends Application implements ReactApplication { //属性 private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { //返回了ReactPackage的子类MainReactPackage return Arrays.<ReactPackage>asList( new MainReactPackage() ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); }}public interface ReactApplication { /** * Get the default {@link ReactNativeHost} for this app. * 获取react-native的配置类 */ ReactNativeHost getReactNativeHost();}
ReactPackage是设置配置信息的接口,如下:
public interface ReactPackage { //返回原生模块的配置集合,用于js代码调用原生代码 List<NativeModule> createNativeModules(ReactApplicationContext reactContext); //返回js模块的配置集合,用于原生代码调用js代码 List<Class<? extends JavaScriptModule>> createJSModules(); List<ViewManager> createViewManagers(ReactApplicationContext reactContext);}
ReactPackage有两个子类MainReactPackage、CoreModulesPackage后面初始化的时候会用到。其中MainReactPackage里面有网络请求模块的相关配置,如下:
public List<ModuleSpec> getNativeModules(final ReactApplicationContext reactContext) { List<ModuleSpec> moduleSpecList = new ArrayList<>(); moduleSpecList.add(new ModuleSpec(NetworkingModule.class, new Provider<NativeModule>() { @Override public NativeModule get() { //网络请求的module return new NetworkingModule(context); } }); //这里省略了其他模块 return moduleSpecList;
MainActivity
public class MainActivity extends ReactActivity { /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "AwesomeProject"; }}
MainActivity继承了ReactActivity
public abstract class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { private final ReactActivityDelegate mDelegate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //调用了ReactActivityDelegate的onCreate方法 mDelegate.onCreate(savedInstanceState); } @Override protected void onPause() { super.onPause(); mDelegate.onPause(); } @Override protected void onResume() { super.onResume(); mDelegate.onResume(); } @Override protected void onDestroy() { super.onDestroy(); mDelegate.onDestroy(); }
ReactActivityDelegate
protected void onCreate(Bundle savedInstanceState) { //忽略部分代码 loadApp(mMainComponentName);}protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); //调用了ReactRootView的startReactApplication方法 mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); //设置contentView getPlainActivity().setContentView(mReactRootView); }
ReactRootView.java
public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle launchOptions) { //省略部分代码 mReactInstanceManager = reactInstanceManager; mJSModuleName = moduleName; mLaunchOptions = launchOptions; if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { mReactInstanceManager.createReactContextInBackground(); } }
XReactInstanceManagerImpl.java
public void recreateReactContextInBackground() { recreateReactContextInBackgroundInner();}private void recreateReactContextInBackgroundInner() { recreateReactContextInBackgroundFromBundleLoader();}private void recreateReactContextInBackgroundFromBundleLoader() { recreateReactContextInBackground( new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()), mBundleLoader);}private void recreateReactContextInBackground( JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) { ReactContextInitParams initParams = new ReactContextInitParams(jsExecutorFactory, jsBundleLoader); // No background task to create react context is currently running, create and execute one. //创建了ReactContextInitAsyncTask对象并调用 mReactContextInitAsyncTask = new ReactContextInitAsyncTask(); mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams); }
ReactContextInitAsyncTask.java
private final class ReactContextInitAsyncTask extends AsyncTask<ReactContextInitParams, Void, Result<ReactApplicationContext>> { @Override protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); try { JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create(); return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader())); } catch (Exception e) { // Pass exception to onPostExecute() so it can be handled on the main thread return Result.of(e); } }}
调用了XReactInstanceManagerImpl的createReactContext方法
private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { mSourceUrl = jsBundleLoader.getSourceUrl(); //原生模块集合初始化 List<ModuleSpec> moduleSpecs = new ArrayList<>(); Map<Class, ReactModuleInfo> reactModuleInfoMap = new HashMap<>(); JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder(); final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); try { //ReactPackage的子类,配置文件1 CoreModulesPackage coreModulesPackage = new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider); //这里将coreModulesPackage里面的配置信息解析到moduleSpecs集合中 processPackage( coreModulesPackage, reactContext, moduleSpecs, reactModuleInfoMap, jsModulesBuilder); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } //mPackages集合中存在MainReactPackage的对象,是在XReactInstanceManagerImpl构造函数中赋值的 for (ReactPackage reactPackage : mPackages) { try { //这里将reactPackage里面的配置信息解析到moduleSpecs集合中 processPackage( reactPackage, reactContext, moduleSpecs, reactModuleInfoMap, jsModulesBuilder); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } //省略部分代码 //剩下代码下面内容会分析 }
先看processPackage方法
private void processPackage( ReactPackage reactPackage, ReactApplicationContext reactContext, List<ModuleSpec> moduleSpecs, Map<Class, ReactModuleInfo> reactModuleInfoMap, JavaScriptModuleRegistry.Builder jsModulesBuilder) { //获取原生模块配置、解析添加到moduleSpecs中 for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) { moduleSpecs.add( new ModuleSpec(nativeModule.getClass(), new EagerModuleProvider(nativeModule))); } for (Class<? extends JavaScriptModule> jsModuleClass : reactPackage.createJSModules()) { jsModulesBuilder.add(jsModuleClass); } }//LazyReactPackage.java中的方法@Override public final List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); for (ModuleSpec holder : getNativeModules(reactContext)) { modules.add(holder.getProvider().get()); } return modules; }//MainReactPackage.java中的方法,里面有网络请求等原生模块的初始化配置信息public List<ModuleSpec> getNativeModules(final ReactApplicationContext reactContext) { List<ModuleSpec> moduleSpecList = new ArrayList<>(); moduleSpecList.add(new ModuleSpec(NetworkingModule.class, new Provider<NativeModule>() { @Override public NativeModule get() { //网络请求的module return new NetworkingModule(context); } }); //这里省略了其他模块 return moduleSpecList;
经过processPackage方法,moduleSpecs里面就存放了所有原生模块的配置信息。
createReactContext方法调用完processPackage后的代码片段如下:
private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { //moduleSpecs构造NativeModuleRegistry对象 NativeModuleRegistry nativeModuleRegistry = new NativeModuleRegistry(moduleSpecs, reactModuleInfoMap); CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSModuleRegistry(jsModulesBuilder.build()) .setJSBundleLoader(jsBundleLoader); final CatalystInstance catalystInstance = catalystInstanceBuilder.build(); reactContext.initializeWithInstance(catalystInstance); catalystInstance.runJSBundle(); return reactContext; }
moduleSpecs配置信息构造了NativeModuleRegistry对象:
//成员遍历,保存所有原生模块private final Map<Class<? extends NativeModule>, ModuleHolder> mModules;public NativeModuleRegistry( List<ModuleSpec> moduleSpecList, Map<Class, ReactModuleInfo> reactModuleInfoMap) { Map<String, Pair<Class<? extends NativeModule>, ModuleHolder>> namesToSpecs = new HashMap<>(); //遍历原生模块配置集合moduleSpecList的每一个模块配置 for (ModuleSpec module : moduleSpecList) { Class<? extends NativeModule> type = module.getType(); ModuleHolder holder = new ModuleHolder( type, reactModuleInfoMap.get(type), module.getProvider()); String name = holder.getInfo().name(); Class<? extends NativeModule> existing = namesToSpecs.containsKey(name) ? namesToSpecs.get(name).first : null; namesToSpecs.put(name, new Pair<Class<? extends NativeModule>, ModuleHolder>(type, holder)); } mModules = new HashMap<>(); for (Pair<Class<? extends NativeModule>, ModuleHolder> pair : namesToSpecs.values()) { //添加配置信息到原生模块集合中 mModules.put(pair.first, pair.second); } }
接下来将创建的nativeModuleRegistry对象传递给CatalystInstanceImpl.Builder对象并调用build()方法构造CatalystInstanceImpl对象
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSModuleRegistry(jsModulesBuilder.build()) .setJSBundleLoader(jsBundleLoader) .setNativeModuleCallExceptionHandler(exceptionHandler);final CatalystInstance catalystInstancecatalystInstance = catalystInstanceBuilder.build();
CatalystInstanceImpl的构造方法如下:
private CatalystInstanceImpl( final ReactQueueConfigurationSpec ReactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry registry, final JavaScriptModuleRegistry jsModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { mHybridData = initHybrid(); mReactQueueConfiguration = ReactQueueConfigurationImpl.create( ReactQueueConfigurationSpec, new NativeExceptionHandler()); mBridgeIdleListeners = new CopyOnWriteArrayList<>(); //原生模块赋值给了成员变量mJavaRegistry mJavaRegistry = registry; mJSModuleRegistry = jsModuleRegistry; mJSBundleLoader = jsBundleLoader; mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; mTraceListener = new JSProfilerTraceListener(this); initializeBridge( new BridgeCallback(this), jsExecutor, mReactQueueConfiguration.getJSQueueThread(), mReactQueueConfiguration.getNativeModulesQueueThread(), //调用了NativeModuleRegistry的getModuleRegistryHolder方法 mJavaRegistry.getModuleRegistryHolder(this)); mMainExecutorToken = getMainExecutorToken(); }
NativeModuleRegistry.java
ModuleRegistryHolder getModuleRegistryHolder( CatalystInstanceImpl catalystInstanceImpl) { ArrayList<JavaModuleWrapper> javaModules = new ArrayList<>(); ArrayList<CxxModuleWrapper> cxxModules = new ArrayList<>(); //遍历所有module,添加到javaModules集合中 for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) { Class<?> type = entry.getKey(); ModuleHolder moduleHolder = entry.getValue(); if (BaseJavaModule.class.isAssignableFrom(type)) { javaModules.add(new JavaModuleWrapper(catalystInstanceImpl, moduleHolder)); } else if (CxxModuleWrapper.class.isAssignableFrom(type)) { cxxModules.add((CxxModuleWrapper) moduleHolder.getModule()); } else { throw new IllegalArgumentException("Unknown module type " + type); } } //返回 ModuleRegistryHolder对象 return new ModuleRegistryHolder(catalystInstanceImpl, javaModules, cxxModules); }
ModuleRegistryHolder.java
public class ModuleRegistryHolder { private final HybridData mHybridData; //将javaModules原生模块配置信息通过JNI传递到了C++层 private static native HybridData initHybrid( CatalystInstanceImpl catalystInstanceImpl, Collection<JavaModuleWrapper> javaModules, Collection<CxxModuleWrapper> cxxModules); public ModuleRegistryHolder(CatalystInstanceImpl catalystInstanceImpl, Collection<JavaModuleWrapper> javaModules, Collection<CxxModuleWrapper> cxxModules) { //调用native方法 mHybridData = initHybrid(catalystInstanceImpl, javaModules, cxxModules); }}
返回的ModuleRegistryHolder对象,传递给了CatalystInstanceImpl的native方法initializeBridge,如下:
private native void initializeBridge(ReactCallback callback, JavaScriptExecutor jsExecutor, MessageQueueThread jsQueue, MessageQueueThread moduleQueue, ModuleRegistryHolder registryHolder);
初始化c层
c++代码看不太懂,调用流程走不通。请指教。
下面只列出了关键代码:
ProxyExecutor::ProxyExecutor(jni::global_ref<jobject>&& executorInstance, std::shared_ptr<ExecutorDelegate> delegate) : m_executor(std::move(executorInstance)) , m_delegate(delegate) { folly::dynamic nativeModuleConfig = folly::dynamic::array; { SystraceSection s("collectNativeModuleDescriptions"); //获取原生模块配置集合 auto moduleRegistry = delegate->getModuleRegistry(); //遍历集合,将配置信息添加到nativeModuleConfig中 for (const auto& name : moduleRegistry->moduleNames()) { auto config = moduleRegistry->getConfig(name); nativeModuleConfig.push_back(config ? config->config : nullptr); } } //remoteModuleConfig是__fbBatchedBridgeConfig变量的一个属性,值为nativeModuleConfig folly::dynamic config = folly::dynamic::object ("remoteModuleConfig", std::move(nativeModuleConfig)); SystraceSection t("setGlobalVariable"); //设置了js全局变量__fbBatchedBridgeConfig为config的json格式字符串 setGlobalVariable( "__fbBatchedBridgeConfig", folly::make_unique<JSBigStdString>(folly::toJson(config)));}
初始化小结
应用启动的时候(ReactActivity onCreate方法被调用)初始化了所有java模块,并将java模块信息设置成js全局变量__fbBatchedBridgeConfig以供调用。以网络模块举例如下:
NetworkingModule.java里面是网络请求模块提供的三个网络请求方法:
@ReactModule(name = "RCTNetworking", supportsWebWorkers = true)public final class NetworkingModule extends ReactContextBaseJavaModule {//发送请求@ReactMethodpublic void sendRequest( final ExecutorToken executorToken, String method, String url, final int requestId, ReadableArray headers, ReadableMap data, final String responseType, final boolean useIncrementalUpdates, int timeout) {//省略代码}}//取消请求@ReactMethod public void abortRequest(ExecutorToken executorToken, final int requestId) { //省略代码 }//清除cookie @ReactMethod public void clearCookies( ExecutorToken executorToken, com.facebook.react.bridge.Callback callback) { //省略代码 }
对应js端:
这样android端所有可以被js端调用的模块信息都暴露给了js,完成了初始化过程。
网络请求
网络请求js层
- 1.用户点击“点我测试网络”后,会执行以下js方法:
function requestFromServer(...props) { this.url = props.shift(1); this.options = props.shift(1); //调用了fetch函数 return fetch(this.url, Object.assign({}, this.options)) .then((response) => { return response.json() });}
- 2.fetch.js
fetch函数定义在fetch.js中
self.fetch = function(input, init) { //参数input是请求的url //init是请求参数,包括请求方式get、header等 return new Promise(function(resolve, reject) { var request = new Request(input, init) var xhr = new XMLHttpRequest() //省略部分代码 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) }) }
该函数返回了一个Promise对象,该对象定义在core.js中
function Promise(fn) { //忽略部分代码 doResolve(fn, this);}
调用了doResolve方法:
function doResolve(fn, promise) { var done = false; var res = tryCallTwo(fn, function (value) {//参数a if (done) return; done = true; resolve(promise, value); }, function (reason) {//参数b if (done) return; done = true; reject(promise, reason); }) //忽略部分代码}function tryCallTwo(fn, a, b) { try { fn(a, b); } catch (ex) { LAST_ERROR = ex; return IS_ERROR; }}
- 3.doResolve内部调用了tryCallTwo方法。绕了半天,上面代码可以简单概括为
var xhr = new XMLHttpRequest() //省略部分代码 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
xhr.send定义在XMLHttpRequest.js中
send(data: any): void { //省略部分代码 RCTNetworking.sendRequest( this._method, this._trackingName, this._url, this._headers, data, nativeResponseType, incrementalEvents, this.timeout, this.__didCreateRequest.bind(this), ); }
调用了RCTNeworking的sendRequest方法
sendRequest( method: string, trackingName: string, url: string, headers: Object, data: string | FormData | {uri: string}, responseType: 'text' | 'base64', incrementalUpdates: boolean, timeout: number, callback: (requestId: number) => any ) { const body = typeof data === 'string' ? {string: data} : data instanceof FormData ? {formData: getParts(data)} : data; const requestId = generateRequestId(); RCTNetworkingNative.sendRequest( method, url, requestId, convertHeadersMapToArray(headers), {...body, trackingName}, responseType, incrementalUpdates, timeout ); callback(requestId); }
调用了RCTNetworkNative的sendRequest方法。
//RCTNetworkingNative的定义const RCTNetworkingNative = require('NativeModules').Networking;
- 4.原生代码模块js端初始化
require(‘NativeModules’)的定义及赋值在NativeModules.js中:
let NativeModules : {[moduleName: string]: Object} = {};//定义 //上面初始化部分提到过:__fbBatchedBridgeConfig这个全局变量,是在初始化时通过JNI代码设置的。 //里面是所有暴露给js方法调用的模块。 const bridgeConfig = global.__fbBatchedBridgeConfig; //遍历所有模块 (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => { // Initially this config will only contain the module name when running in JSC. The actual // configuration of the module will be lazily loaded. const info = genModule(config, moduleID);//生成每一个模块的所有方法 if (!info) { return; } //省略部分代码 if (info.module) { //上面的对象NativeModules.Networking就是这么生成的 NativeModules[info.name] = info.module; } });
//生成模块function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} { if (!config) { return null; } const [moduleName, constants, methods, promiseMethods, syncMethods] = config; const module = {}; //遍历该模块所有方法配置 methods && methods.forEach((methodName, methodID) => { const isPromise = promiseMethods && arrayContains(promiseMethods, methodID); const isSync = syncMethods && arrayContains(syncMethods, methodID); const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async'; //调用genMethod生成方法 module[methodName] = genMethod(moduleID, methodID, methodType); }); Object.assign(module, constants); return { name: moduleName, module };}//动态生成模块里面的方法function genMethod(moduleID: number, methodID: number, type: MethodType) { let fn = null; if (type === 'promise') {//promise类型 fn = function(...args: Array<any>) { return new Promise((resolve, reject) => { BatchedBridge.enqueueNativeCall(moduleID, methodID, args, (data) => resolve(data), (errorData) => reject(createErrorFromErrorData(errorData))); }); }; } else if (type === 'sync') {//sync类型 fn = function(...args: Array<any>) { return global.nativeCallSyncHook(moduleID, methodID, args); }; } else {//普通类型 //fn就是根据配置动态生成的方法 //RCTNetworkingNative.sendRequest这个方法就是动态生成的 fn = function(...args: Array<any>) { const lastArg = args.length > 0 ? args[args.length - 1] : null; const secondLastArg = args.length > 1 ? args[args.length - 2] : null; const hasSuccessCallback = typeof lastArg === 'function'; const hasErrorCallback = typeof secondLastArg === 'function'; hasErrorCallback && invariant( hasSuccessCallback, 'Cannot have a non-function arg after a function arg.' ); const onSuccess = hasSuccessCallback ? lastArg : null; const onFail = hasErrorCallback ? secondLastArg : null; const callbackCount = hasSuccessCallback + hasErrorCallback; args = args.slice(0, args.length - callbackCount); BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess); }; } fn.type = type; return fn;}
BatchedBridge.enqueueNativeCall定义在MessageQueue.js中
enqueueNativeCall(moduleID: number, methodID: number, params: Array<any>, onFail: ?Function, onSucc: ?Function) { if (onFail || onSucc) { onFail && params.push(this._callbackID); this._callbacks[this._callbackID++] = onFail; onSucc && params.push(this._callbackID); this._callbacks[this._callbackID++] = onSucc; } this._callID++; this._queue[MODULE_IDS].push(moduleID);//模块Id放入数组 this._queue[METHOD_IDS].push(methodID)//方法Id放入数组 this._queue[PARAMS].push(params);//参数放入数组 }
这里把要调用的模块id、方法id、参数放入_queue数组中。
原生代码会轮询查询_queue方法里是否有数据:
//JNI代码调用情况1callFunctionReturnFlushedQueue(module: string, method: string, args: Array<any>) { this.__callFunction(module, method, args); this.__callImmediates(); return this.flushedQueue(); } //JNI代码调用情况2 callFunctionReturnResultAndFlushedQueue(module: string, method: string, args: Array<any>) { let result; result = this.__callFunction(module, method, args); this.__callImmediates(); return [result, this.flushedQueue()]; } //JNI代码调用情况3 invokeCallbackAndReturnFlushedQueue(cbID: number, args: Array<any>) { this.__invokeCallback(cbID, args); this.__callImmediates(); return this.flushedQueue(); } flushedQueue() { this.__callImmediates(); const queue = this._queue; this._queue = [[], [], [], this._callID]; return queue[0].length ? queue : null;//这里返回了queue里面的内容 }
网络请求c层
JNI代码会调用flushedQueue方法,从而调用相应的原生模块中对应的方法,完成js到native端通信
c++代码不熟,水平不够(JNI端实现原理请参考系列文章:http://blog.csdn.net/MegatronKings/article/category/6377857)
网络请求java层
- 打断点原生代码入口是NativeRunnable,如下:
/** * A Runnable that has a native run implementation. */@DoNotStrippublic class NativeRunnable implements Runnable { private final HybridData mHybridData; @DoNotStrip private NativeRunnable(HybridData hybridData) { mHybridData = hybridData; } public native void run();}
- 调用JavaModuleWrapper的invoke方法:
@DoNotStrip public void invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters) { if (mMethods == null || methodId >= mMethods.size()) { return; } mMethods.get(methodId).invoke(mCatalystInstance, token, parameters); }
其中参数parameters是一个数组,里面有各种网络参数,如下:
[“GET”,”https://free-api.heweather.com/v5//now?city=beijing&key=9e6aa5cbcb994295ae8e54da94f48bba“,4,[[“accept”,”application/json”],[“content-type”,”application/json”]],{“trackingName”:”unknown”},”text”,false,0]
- 调用JavaMethod的invoke方法:
@Override public void invoke(CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray parameters) { //省略部分代码 mMethod.invoke(BaseJavaModule.this, mArguments); //省略部分代码 }
mMethod是NetworkingModule类的sendRequest方法:
- NetworkingModule.sendRequest方法
//实现这个注解的方法代表暴露给JNI的方法@ReactMethod /** * @param timeout value of 0 results in no timeout */ public void sendRequest( final ExecutorToken executorToken, String method,//GET、POST等 String url,//请求URL final int requestId,//请求tag ReadableArray headers,//请求header ReadableMap data,//请求数据 final String responseType,//期望返回数据格式 final boolean useIncrementalUpdates, int timeout) { Request.Builder requestBuilder = new Request.Builder().url(url);//网络请求使用OkHttp if (requestId != 0) { requestBuilder.tag(requestId); } //内部通过动态代理创建RCTDeviceEventEmitter的实例:用于将网络请求返回的数据返回给JNI端 final RCTDeviceEventEmitter eventEmitter = getEventEmitter(executorToken); OkHttpClient.Builder clientBuilder = mClient.newBuilder(); if (timeout != mClient.connectTimeoutMillis()) { clientBuilder.readTimeout(timeout, TimeUnit.MILLISECONDS); } OkHttpClient client = clientBuilder.build(); Headers requestHeaders = extractHeaders(headers, data); if (requestHeaders == null) { ResponseUtil.onRequestError(eventEmitter, requestId, "Unrecognized headers format", null); return; } String contentType = requestHeaders.get(CONTENT_TYPE_HEADER_NAME); String contentEncoding = requestHeaders.get(CONTENT_ENCODING_HEADER_NAME); requestBuilder.headers(requestHeaders); //忽略部分代码 // Nothing in data payload, at least nothing we could understand anyway. requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); client.newCall(requestBuilder.build()).enqueue(//开始请求网络 new Callback() { @Override public void onFailure(Call call, IOException e) { //请求失败的回调 //忽略部分代码 ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } @Override public void onResponse(Call call, Response response) throws IOException { //请求成功回调 //忽略部分代码 // Before we touch the body send headers to JS 返回headers给JNI ResponseUtil.onResponseReceived( eventEmitter, requestId, response.code(), translateHeaders(response.headers()), response.request().url().toString()); ResponseBody responseBody = response.body(); //忽略部分代码 // Otherwise send the data in one big chunk, in the format that JS requested. String responseString = ""; if (responseType.equals("text")) {//如果请求参数中传递的是text,直接返回字符串 responseString = responseBody.string(); } else if (responseType.equals("base64")) {//请求参数中传递的是base64 responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } //返回response body给JNI ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); ResponseUtil.onRequestSuccess(eventEmitter, requestId); //忽略部分代码 } }); }
可以看到,访问网络使用的是okhttp。根据请求参数构造request,并且加入到okhttp的队列中。这样就开始请求网络了。请求成功或者失败会调用ResponseUtil相应的方法。在成功的回调方法中,先把response的heades返回给JNI端(调用ResponseUtil.onResponseReceived),然后返回response体给JNI端(调用ResponseUtil.onDataReceived方法),最后调用ResponseUtil.onRequestSuccess通知JNI改网络请求完成。
下面只分析.ResponseUtil的onDataReceived方法(其他方法类似)。
网络返回java层
- ResponseUtil的onDataReceived方法
public static void onDataReceived( RCTDeviceEventEmitter eventEmitter,//动态代理生成的对象 int requestId,//请求tag String data) {//response body体中的内容 WritableArray args = Arguments.createArray(); args.pushInt(requestId); args.pushString(data); eventEmitter.emit("didReceiveNetworkData", args);//调用eventEmitter对象的emit方法 }
eventEmitter是通过动态代码生成的对象,如下:
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance( moduleInterface.getClassLoader(), new Class[]{moduleInterface}, new JavaScriptModuleInvocationHandler(executorToken, instance, registration));
可以看到具体实现是在JavaScriptModuleInvocationHandler中:
- JavaScriptModuleInvocationHandler.invoke方法:
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { //省略部分代码 mCatalystInstance.callFunction( executorToken, mModuleRegistration.getName(), method.getName(), jsArgs ); return null; }
- CatalystInstanceImpl.callFunction方法
public void callFunction( ExecutorToken executorToken, final String module,//值为:RCTDeviceEventEmitter final String method, //值为:emit final NativeArray arguments) {//值为:["didReceiveNetworkData",[5,"response body"]] //忽略部分代码 callJSFunction(executorToken, module, method, arguments); }
callJSFunction是c++方法,如下:
private native void callJSFunction( ExecutorToken token, String module, String method, NativeArray arguments);
网络返回c层
CatalystInstanceImpl.cpp
void CatalystInstanceImpl::callJSFunction( JExecutorToken* token, std::string module, std::string method, NativeArray* arguments) { //调用instance的callJSFunction方法 instance_->callJSFunction(token->getExecutorToken(nullptr), std::move(module), std::move(method), std::move(arguments->array));}
Instance.cpp
void Instance::callJSFunction(ExecutorToken token, std::string&& module, std::string&& method, folly::dynamic&& params) { //调用nativeToJsBridge的callFunction方法 nativeToJsBridge_->callFunction(token, std::move(module), std::move(method), std::move(params));}
NativeToJsBridge.cpp
void NativeToJsBridge::callFunction( ExecutorToken executorToken, std::string&& module, std::string&& method, folly::dynamic&& arguments) { int systraceCookie = -1; #ifdef WITH_FBSYSTRACE systraceCookie = m_systraceCookie++; std::string tracingName = fbsystrace_is_tracing(TRACE_TAG_REACT_CXX_BRIDGE) ? folly::to<std::string>("JSCall__", module, '_', method) : std::string(); SystraceSection s(tracingName.c_str()); FbSystraceAsyncFlow::begin( TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str(), systraceCookie); #else std::string tracingName; #endif runOnExecutorQueue(executorToken, [module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie] (JSExecutor* executor) { //调用executor的callFunction // This is safe because we are running on the executor's thread: it won't // destruct until after it's been unregistered (which we check above) and // that will happen on this thread executor->callFunction(module, method, arguments); });}
JSCExecutor.cpp
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { auto result = [&] { try { //调用m_callFunctionReturnFlushedQueueJS方法,并获取返回值(就是前面的queue里面的数据) return m_callFunctionReturnFlushedQueueJS->callAsFunction({ Value(m_context, String::createExpectingAscii(m_context, moduleId)), Value(m_context, String::createExpectingAscii(m_context, methodId)), Value::fromDynamic(m_context, std::move(arguments)) }); } catch (...) { std::throw_with_nested( std::runtime_error("Error calling function: " + moduleId + ":" + methodId)); } }(); //调用原生代码 callNativeModules(std::move(result));}//m_invokeCallbackAndReturnFlushedQueueJS初始化如下void JSCExecutor::bindBridge() throw(JSException) { //获取js根对象 auto global = Object::getGlobalObject(m_context); //获取js全局对象__fbBatchedBridge auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); auto batchedBridge = batchedBridgeValue.asObject(); //__fbBatchedBridge的一个方法 m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject(); //——fbBatchedBridge的一个方法 m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject(); //——fbBatchedBridge的一个方法 m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject(); //——fbBatchedBridge的一个方法 m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();}
__fbBatchedBridge是在BatchedBridge.js中定义好的全局对象,实际上是一个MessageQueue对象
网络返回js层
const MessageQueue = require('MessageQueue');const BatchedBridge = new MessageQueue();Object.defineProperty(global, '__fbBatchedBridge', { configurable: true, value: BatchedBridge,});module.exports = BatchedBridge;
MessageQueue.js中的callFunctionReturnFlushedQueue方法
callFunctionReturnFlushedQueue(module: string, method: string, args: Array<any>) { //执行方法 this.__callFunction(module, method, args); this.__callImmediates(); //将queue数组里面的信息返回JNI端 return this.flushedQueue(); }__callFunction(module: string, method: string, args: Array<any>) { //module 取值为RCTDeviceEventEmitter //method 取值为emit const moduleMethods = this._callableModules[module]; const result = moduleMethods[method].apply(moduleMethods, args); Systrace.endEvent(); return result; }
参数如图所示:
这里调用了RCTDeviceEventEmitter的emit方法并传入了网络请求的response.
到这里response已经返回到js端了。
代码下载
- 示例代码下载地址https://github.com/fightingBirdCaiy/reactNativeLearn.git
参考资料
- 使用及注意事项:http://blog.csdn.net/qq_16086969/article/details/53522980
- 原理介绍:http://blog.csdn.net/MegatronKings/article/category/6377857
- React Native网络请求学习笔记(Android版本)
- React-Native 学习笔记十七(网络请求)
- React Native 学习笔记(九)--网络请求 & 界面跳转
- React-Native学习笔记之:Fetch网络请求
- react native学习笔记8——网络请求
- react native 学习笔记----网络
- react native 学习笔记----网络
- React Native网络请求
- React Native 网络请求
- React Native Android学习笔记
- React-Native中网络请求
- React-native fetch请求网络
- React Native Fetch网络请求
- React-Native 学习笔记
- react native学习笔记
- react-native 学习笔记
- 学习笔记 - React Native
- React Native 学习笔记
- Bootstrap 标签页插件
- 程序中的小细节——datepicker的两种显示方式,spinner和calendar
- linux 安装hadoop是32位的需要手工编译成64位
- 安装Halcon10.0
- Java HashMap分析及其它
- React Native网络请求学习笔记(Android版本)
- C++ 实现反射机制
- 不同形状的头像
- js学习笔记:严格模式
- BZOJ 3672 [Noi2014]购票【点分+斜率优化
- 在Fragment中webView的回退问题
- 系统开发奥若拉模式
- 约瑟夫环
- REDIS 进阶(12) redis分片