React Native网络请求学习笔记(Android版本)

概述

这篇文章首先会展示react native的一个简单的访问网络请求的例子。然后会分析代码的实现。

注:
1.本文示例及代码分析基于react native 0.40版本。
2.限于水平有限,c++代码部分分析比较简单。期望更正,谢谢。

基本示例

注:示例来自http://www.jb51.cc/article/p-fydpvysd-bqm.html,并做了一些修改。

效果

  • 页面初始化的时候展示一个可点击的文本“点我测试网络”。
  • 用户点击文本后,会访问网络和风天气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',},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://www.jb51.cc/article/p-ahzjgpxg-up.html

如上图,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,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<CxxModuleWrapper> cxxModules) {
    //调用native方法 
    mHybridData = initHybrid(catalystInstanceImpl,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 {

//发送请求
@ReactMethod
public 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,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,args,(data) => resolve(data),(errorData) => reject(createErrorFromErrorData(errorData)));
      });
    };
  } else if (type === 'sync') {//sync类型
    fn = function(...args: Array<any>) {
      return global.nativeCallSyncHook(moduleID,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,onFail,onSuccess);
    };
  }
  fn.type = type;
  return fn;
}

BatchedBridge.enqueueNativeCall定义在MessageQueue.js中

enqueueNativeCall(moduleID: 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代码调用情况1
callFunctionReturnFlushedQueue(module: string,method: string,args: Array<any>) {
    this.__callFunction(module,method,args);
    this.__callImmediates();
    return this.flushedQueue();
  }
  //JNI代码调用情况2
  callFunctionReturnResultAndFlushedQueue(module: string,args: Array<any>) {
    let result;
    result = this.__callFunction(module,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. */
@DoNotStrip
public 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,//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,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,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,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,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__",'_',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,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,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,args); this.__callImmediates(); //将queue数组里面的信息返回JNI端 return this.flushedQueue(); }

__callFunction(module: 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端了。

代码下载

参考资料

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom