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
0 0
原创粉丝点击