上一篇文章讲了ios的这里接着讲RN-android-自签名https的配置,首先android比较复杂,首先用AS打开android工程

android有4个地方得改

  1. fetch (.jar包里的代码不能直接改)
  2. webview (.jar包里的代码不能直接改)
  3. Image (.jar包里的代码不能直接改--)
  4. react-native-fetch-blob(可以直接改源码-RNFetchBlobReq
    RNFetchBlob 这两个类)
  5. 如果使用了react-native-navigation时,在我们copy出MainReactPackage使用时会报错,注释掉react-native-navigation报错的地方就行

注意:RN的不同版本,会有不同的依赖问题,得根据报错一个一个改,很麻烦

fetch

  • 修改路径和原理
    安卓三方的依赖库在这可以看到


    RN集成自签名https及双向认证-android(2)_第1张图片 AADFC784-0EDE-4B65-8633-7577568F4294.png
RN集成自签名https及双向认证-android(2)_第2张图片 17A28174-6D4C-4C0C-9773-FA77D93D2C0F.png

NetworkingModule.java文件就是我们android最底层的网络请求工具类,每次创建NetworkingModule对象的时候,我们会传入一个okhttpclient的对象:

public NetworkingModule(ReactApplicationContext context) {        this(context, (String)null, OkHttpClientProvider.createClient(), (List)null);    }    public NetworkingModule(ReactApplicationContext context, List networkInterceptorCreators) {        this(context, (String)null, OkHttpClientProvider.createClient(), networkInterceptorCreators);    }    public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {        this(context, defaultUserAgent, OkHttpClientProvider.createClient(), (List)null);    }

可以看到,每次都是通过:

OkHttpClientProvider.createClient()

的方式创建了一个okhttpclient对象,最后发送请求为:

 @ReactMethod    public void sendRequest(ExecutorToken executorToken, String method, String url, final int requestId, ReadableArray headers, ReadableMap data, final String responseType, final boolean useIncrementalUpdates, int timeout) {        okhttp3.Request.Builder requestBuilder = (new okhttp3.Request.Builder()).url(url);        if(requestId != 0) {            requestBuilder.tag(Integer.valueOf(requestId));        }        final RCTDeviceEventEmitter eventEmitter = this.getEventEmitter(executorToken);        Builder clientBuilder = this.mClient.newBuilder();        ....

所以我们只需要替换掉默认的httpclient,然后为其添加上证书认证就可以了,我们打开 OkHttpClientProvider.createClient()方法:

 public static OkHttpClient createClient() {        Builder client = (new Builder()).connectTimeout(0L, TimeUnit.MILLISECONDS).readTimeout(0L, TimeUnit.MILLISECONDS).writeTimeout(0L, TimeUnit.MILLISECONDS).cookieJar(new ReactCookieJarContainer());        return enableTls12OnPreLollipop(client).build();    }

OkHttpClientProvider这个工具类就是为我们提供了一个修改默认okhttpclient的方法,我们看到其中有一个方法:

public static void replaceOkHttpClient(OkHttpClient client) {        sClient = client;    }

这个方法就是替换掉rn中网络请求默认的okhttpclient方法。
所以我们在程序初始化的时候改掉默认的okhttpclient.

  1. 首先找到你项目的application文件,在oncreate方法中提供其方法:
 @Override    public void onCreate() {      ...        //RN OKHTTP添加https证书        OkHttpClientProvider.replaceOkHttpClient(initCustomOkHttpClient());      ...    }//自定义初始化client方法-public OkHttpClient initCustomOkHttpClient() {        OkHttpClient.Builder client = new OkHttpClient.Builder()                .connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .readTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .writeTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .cookieJar(new ReactCookieJarContainer());        client.addNetworkInterceptor(new StethoInterceptor());        client.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));        try {        //你的证书文件,放在android的assets文件夹下            setCertificates(client, getAssets().open("CA.crt"));            client.hostnameVerifier(new HostnameVerifier() {                @Override                public boolean verify(String hostname, SSLSession session) {                    return true;                }            });        } catch (IOException e) {            e.printStackTrace();        }        OkHttpClient.Builder builder = OkHttpClientProvider.enableTls12OnPreLollipop(client);        return builder.build();    }//处理证书public void setCertificates(OkHttpClient.Builder client, InputStream... certificates) {        try {            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());            keyStore.load(null);            int index = 0;            for (InputStream certificate : certificates) {                String certificateAlias = Integer.toString(index++);                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));                try {                    if (certificate != null)                        certificate.close();                } catch (IOException e) {                }            }            SSLContext sslContext = SSLContext.getInstance("TLS");            TrustManagerFactory trustManagerFactory =                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());            trustManagerFactory.init(keyStore);            sslContext.init(                    null,                    trustManagerFactory.getTrustManagers(),                    new SecureRandom()            );            client.sslSocketFactory(sslContext.getSocketFactory());        } catch (Exception e) {            e.printStackTrace();        }    }
  1. 修改NetworkingModule.java文件的以下方法,把默认创建okhttpclient的方式:OkHttpClientProvider.createClient(),全部改为:OkHttpClientProvider.getOkHttpClient()
public NetworkingModule(ReactApplicationContext context) {        this(context, (String)null, OkHttpClientProvider.createClient(), (List)null);    }    public NetworkingModule(ReactApplicationContext context, List networkInterceptorCreators) {        this(context, (String)null, OkHttpClientProvider.createClient(), networkInterceptorCreators);    }    public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {        this(context, defaultUserAgent, OkHttpClientProvider.createClient(), (List)null);    }

如下:

  /**   * @param context the ReactContext of the application   */  public NetworkingModule(final ReactApplicationContext context) {    this(context, null, OkHttpClientProvider.getOkHttpClient(), null);  }  /**   * @param context the ReactContext of the application   * @param networkInterceptorCreators list of {@link NetworkInterceptorCreator}'s whose create()   * methods would be called to attach the interceptors to the client.   */  public NetworkingModule(    ReactApplicationContext context,    List networkInterceptorCreators) {    this(context, null, OkHttpClientProvider.getOkHttpClient(), networkInterceptorCreators);  }  /**   * @param context the ReactContext of the application   * @param defaultUserAgent the User-Agent header that will be set for all requests where the   * caller does not provide one explicitly   */  public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {    this(context, defaultUserAgent, OkHttpClientProvider.getOkHttpClient(), null);  }

问题:react-native的第三方依赖库,改不了源码咋办呢?
我们直接copy一份NetworkingModule跟mainreactpackage的代码,然后在application中把mainreactpackage替换成我们copy出去的那一份,

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {        @Override        public boolean getUseDeveloperSupport() {            return BuildConfig.DEBUG;        }        @Override        protected List getPackages() {            return Arrays.asList(            //替换成我们copy的那个文件                    new MainReactPackage(),                    new VectorIconsPackage(),                    new RCTSplashScreenPackage(),                    new RNDeviceInfo(),                    new AndroidModulePackage(),                    new RCTSwipeRefreshLayoutPackage()            );        }    };

然后点进我们copy的那个MainReactPackage文件,再把MainReactPackage中的:

new ModuleSpec(NetworkingModule.class, new Provider() {        @Override        public NativeModule get() {        //替换成我们自己copy的那个文件          return new NetworkingModule(context);        }      }),
MainReactPackage路径.png
  • Image部分


    RN集成自签名https及双向认证-android(2)_第3张图片 android_Image路径.png
RN集成自签名https及双向认证-android(2)_第4张图片 android图片https修改的地方.png

但是RN对应的那一部分.jar包是不可改的,,主要的问题还是怎么去改动代码

摘要 :

如何改动android.jar 包rn_androi_https

RN集成自签名https及双向认证-android(2)_第5张图片 https需要复制出来的文件.png
MainReactPackage路径.png

  • webView
    • ReactWebviewManager.java
/*** Copyright (c) 2015-present, Facebook, Inc.* All rights reserved.* 

* This source code is licensed under the BSD-style license found in the* LICENSE file in the root directory of this source tree. An additional grant* of patent rights can be found in the PATENTS file in the same directory.*/package petrochina.cplh.qqgl2.htttps;import android.content.ActivityNotFoundException;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.Picture;import android.net.Uri;import android.os.Build;import android.text.TextUtils;import android.util.Log;import android.view.ViewGroup.LayoutParams;import android.webkit.ConsoleMessage;import android.webkit.CookieManager;import android.webkit.GeolocationPermissions;import android.webkit.JavascriptInterface;import android.webkit.ValueCallback;import android.webkit.WebChromeClient;import android.webkit.WebResourceResponse;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import com.facebook.common.logging.FLog;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.LifecycleEventListener;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.ReadableArray;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.ReadableMapKeySetIterator;import com.facebook.react.bridge.WritableMap;import com.facebook.react.common.MapBuilder;import com.facebook.react.common.ReactConstants;import com.facebook.react.common.build.ReactBuildConfig;import com.facebook.react.module.annotations.ReactModule;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;import com.facebook.react.uimanager.UIManagerModule;import com.facebook.react.uimanager.annotations.ReactProp;import com.facebook.react.uimanager.events.ContentSizeChangeEvent;import com.facebook.react.uimanager.events.Event;import com.facebook.react.uimanager.events.EventDispatcher;import com.facebook.react.views.webview.WebViewConfig;import com.facebook.react.views.webview.events.TopLoadingErrorEvent;import com.facebook.react.views.webview.events.TopLoadingFinishEvent;import com.facebook.react.views.webview.events.TopLoadingStartEvent;import com.facebook.react.views.webview.events.TopMessageEvent;import org.json.JSONException;import org.json.JSONObject;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.URL;import java.security.KeyStore;import java.security.cert.CertificateFactory;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;import javax.annotation.Nullable;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.KeyManagerFactory;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSession;import javax.net.ssl.TrustManagerFactory;/*** Manages instances of {@link WebView}*

* Can accept following commands:* - GO_BACK* - GO_FORWARD* - RELOAD*

* {@link WebView} instances could emit following direct events:* - topLoadingFinish* - topLoadingStart* - topLoadingError*

* Each event will carry the following properties:* - target - view's react tag* - url - url set for the webview* - loading - whether webview is in a loading state* - title - title of the current page* - canGoBack - boolean, whether there is anything on a history stack to go back* - canGoForward - boolean, whether it is possible to request GO_FORWARD command*/@ReactModule(name = ReactWebViewManager.REACT_CLASS)public class ReactWebViewManager extends SimpleViewManager { protected static final String REACT_CLASS = "RCTWebView"; protected static final String HTML_ENCODING = "UTF-8"; protected static final String HTML_MIME_TYPE = "text/html"; protected static final String BRIDGE_NAME = "__REACT_WEB_VIEW_BRIDGE"; protected static final String HTTP_METHOD_POST = "POST"; public static final int COMMAND_GO_BACK = 1; public static final int COMMAND_GO_FORWARD = 2; public static final int COMMAND_RELOAD = 3; public static final int COMMAND_STOP_LOADING = 4; public static final int COMMAND_POST_MESSAGE = 5; public static final int COMMAND_INJECT_JAVASCRIPT = 6; // Use `webView.loadUrl("about:blank")` to reliably reset the view // state and release page resources (including any running JavaScript). protected static final String BLANK_URL = "about:blank"; protected WebViewConfig mWebViewConfig; protected @Nullable WebView.PictureListener mPictureListener; private static ThemedReactContext reactContext; protected static class ReactWebViewClient extends WebViewClient { // ---https 双向认证------ private SSLContext sslContext; public ReactWebViewClient() { // 添加https证书 try { InputStream is = reactContext.getAssets().open("CNPCCA.cer"); NetConfig.addCertificate(is); // 这里将证书读取出来,,放在配置中byte[]里 } catch (IOException ioe) { ioe.printStackTrace(); } // 添加证书cer List certificates = new ArrayList<>(); List certs_data = NetConfig.getCertificatesData(); // 将字节数组转为数组输入流 if (certs_data != null && !certs_data.isEmpty()) { for (byte[] bytes : certs_data) { certificates.add(new ByteArrayInputStream(bytes)); } } try { prepareSslPinning(certificates); } catch (IOException e) { e.printStackTrace(); } } @Override public WebResourceResponse shouldInterceptRequest(final WebView view, String url) { Log.i("shouldInterceptRequest", "shouldInterceptRequest1"); if (url.indexOf("https") != -1) { return processRequest(url); } else { return null; } } private WebResourceResponse processRequest(String webUrl) {// LogUtils.i("SSL_PINNING_WEBVIEWS", "GET: " + webUrl.toString()); try { // Setup connection URL url = new URL(webUrl); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); // Set SSL Socket Factory for this request urlConnection.setSSLSocketFactory(sslContext.getSocketFactory()); urlConnection.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } });//很重要,校验证书 // Get content, contentType and encoding InputStream is = urlConnection.getInputStream(); String contentType = urlConnection.getContentType(); String encoding = urlConnection.getContentEncoding(); // If got a contentType header if (contentType != null) { String mimeType = contentType; // Parse mime type from contenttype string if (contentType.contains(";")) { mimeType = contentType.split(";")[0].trim(); }// LogUtils.i("SSL_PINNING_WEBVIEWS", "Mime: " + mimeType); // Return the response return new WebResourceResponse(mimeType, encoding, is); } } catch (Exception e) { e.printStackTrace();// LogUtils.i("SSL_PINNING_WEBVIEWS", e.getLocalizedMessage()); } // Return empty response for this request return new WebResourceResponse(null, null, null); } private void prepareSslPinning(List certificates) throws IOException { try { // 服务器端需要验证的客户端证书,其实就是客户端的keystore KeyManagerFactory keyManagerFactory = KeyManagerFactory .getInstance("X509"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); KeyStore keyStore = KeyStore.getInstance("PKCS12"); KeyStore keyStore2 = KeyStore.getInstance(KeyStore.getDefaultType()); //读取证书 InputStream ksIn = reactContext.getResources().getAssets().open("client.p12");//***:你的p12证书 //加载证书 keyStore2.load(null); keyStore.load(ksIn, "cplh123456".toCharArray());//***:p12证书的密码,必须 ksIn.close(); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); try { for (int i = 0, size = certificates.size(); i < size; ) { InputStream certificate = certificates.get(i); String certificateAlias = Integer.toString(i++); keyStore2.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); if (certificate != null) certificate.close(); } } catch (IOException e) { e.printStackTrace(); } sslContext = SSLContext.getInstance("TLS");// TrustManagerFactory trustManagerFactory =//// TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "cplh123456".toCharArray()); trustManagerFactory.init(keyStore2); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); } catch (Exception e) { e.printStackTrace(); } } // ---https 双向认证------ protected boolean mLastLoadFailed = false; protected @Nullable ReadableArray mUrlPrefixesForDefaultIntent; @Override public void onPageFinished(WebView webView, String url) { super.onPageFinished(webView, url); if (!mLastLoadFailed) { ReactWebView reactWebView = (ReactWebView) webView; reactWebView.callInjectedJavaScript(); reactWebView.linkBridge(); emitFinishEvent(webView, url); } } @Override public void onPageStarted(WebView webView, String url, Bitmap favicon) { super.onPageStarted(webView, url, favicon); mLastLoadFailed = false; dispatchEvent( webView, new TopLoadingStartEvent( webView.getId(), createWebViewEvent(webView, url))); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { boolean useDefaultIntent = false; if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) { ArrayList urlPrefixesForDefaultIntent = mUrlPrefixesForDefaultIntent.toArrayList(); for (Object urlPrefix : urlPrefixesForDefaultIntent) { if (url.startsWith((String) urlPrefix)) { useDefaultIntent = true; break; } } } if (!useDefaultIntent && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://") || url.equals("about:blank"))) { return false; } else { try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); view.getContext().startActivity(intent); } catch (ActivityNotFoundException e) { FLog.w(ReactConstants.TAG, "activity not found to handle uri scheme for: " + url, e); } return true; } } @Override public void onReceivedError( WebView webView, int errorCode, String description, String failingUrl) { super.onReceivedError(webView, errorCode, description, failingUrl); mLastLoadFailed = true; // In case of an error JS side expect to get a finish event first, and then get an error event // Android WebView does it in the opposite way, so we need to simulate that behavior emitFinishEvent(webView, failingUrl); WritableMap eventData = createWebViewEvent(webView, failingUrl); eventData.putDouble("code", errorCode); eventData.putString("description", description); dispatchEvent( webView, new TopLoadingErrorEvent(webView.getId(), eventData)); } protected void emitFinishEvent(WebView webView, String url) { dispatchEvent( webView, new TopLoadingFinishEvent( webView.getId(), createWebViewEvent(webView, url))); } protected WritableMap createWebViewEvent(WebView webView, String url) { WritableMap event = Arguments.createMap(); event.putDouble("target", webView.getId()); // Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks // like onPageFinished event.putString("url", url); event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100); event.putString("title", webView.getTitle()); event.putBoolean("canGoBack", webView.canGoBack()); event.putBoolean("canGoForward", webView.canGoForward()); return event; } public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) { mUrlPrefixesForDefaultIntent = specialUrls; } } /** * Subclass of {@link WebView} that implements {@link LifecycleEventListener} interface in order * to call {@link WebView#destroy} on activity destroy event and also to clear the client */ protected static class ReactWebView extends WebView implements LifecycleEventListener { protected @Nullable String injectedJS; protected boolean messagingEnabled = false; protected @Nullable ReactWebViewClient mReactWebViewClient; protected class ReactWebViewBridge { ReactWebView mContext; ReactWebViewBridge(ReactWebView c) { mContext = c; } @JavascriptInterface public void postMessage(String message) { mContext.onMessage(message); } } /** * WebView must be created with an context of the current activity *

* Activity Context is required for creation of dialogs internally by WebView * Reactive Native needed for access to ReactNative internal system functionality */ public ReactWebView(ThemedReactContext reactContext) { super(reactContext); } @Override public void onHostResume() { // do nothing } @Override public void onHostPause() { // do nothing } @Override public void onHostDestroy() { cleanupCallbacksAndDestroy(); } @Override public void setWebViewClient(WebViewClient client) { super.setWebViewClient(client); mReactWebViewClient = (ReactWebViewClient) client; } public @Nullable ReactWebViewClient getReactWebViewClient() { return mReactWebViewClient; } public void setInjectedJavaScript(@Nullable String js) { injectedJS = js; } protected ReactWebViewBridge createReactWebViewBridge(ReactWebView webView) { return new ReactWebViewBridge(webView); } public void setMessagingEnabled(boolean enabled) { if (messagingEnabled == enabled) { return; } messagingEnabled = enabled; if (enabled) { addJavascriptInterface(createReactWebViewBridge(this), BRIDGE_NAME); linkBridge(); } else { removeJavascriptInterface(BRIDGE_NAME); } } public void callInjectedJavaScript() { if (getSettings().getJavaScriptEnabled() && injectedJS != null && !TextUtils.isEmpty(injectedJS)) { loadUrl("javascript:(function() {\n" + injectedJS + ";\n})();"); } } public void linkBridge() { if (messagingEnabled) { if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // See isNative in lodash String testPostMessageNative = "String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')"; evaluateJavascript(testPostMessageNative, new ValueCallback() { @Override public void onReceiveValue(String value) { if (value.equals("true")) { FLog.w(ReactConstants.TAG, "Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined"); } } }); } loadUrl("javascript:(" + "window.originalPostMessage = window.postMessage," + "window.postMessage = function(data) {" + BRIDGE_NAME + ".postMessage(String(data));" + "}" + ")"); } } public void onMessage(String message) { dispatchEvent(this, new TopMessageEvent(this.getId(), message)); } protected void cleanupCallbacksAndDestroy() { setWebViewClient(null); destroy(); } } public ReactWebViewManager() { mWebViewConfig = new WebViewConfig() { public void configWebView(WebView webView) { } }; } public ReactWebViewManager(WebViewConfig webViewConfig) { mWebViewConfig = webViewConfig; } @Override public String getName() { return REACT_CLASS; } protected ReactWebView createReactWebViewInstance(ThemedReactContext reactContext) { return new ReactWebView(reactContext); } @Override protected WebView createViewInstance(ThemedReactContext reactContext) { ReactWebView webView = createReactWebViewInstance(reactContext); webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onConsoleMessage(ConsoleMessage message) { if (ReactBuildConfig.DEBUG) { return super.onConsoleMessage(message); } // Ignore console logs in non debug builds. return true; } @Override public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { callback.invoke(origin, true, false); } }); reactContext.addLifecycleEventListener(webView); mWebViewConfig.configWebView(webView); webView.getSettings().setBuiltInZoomControls(true); webView.getSettings().setDisplayZoomControls(false); webView.getSettings().setDomStorageEnabled(true); webView.getSettings().setAllowUniversalAccessFromFileURLs(true); webView.getSettings().setAllowFileAccess(true); webView.getSettings().setAllowFileAccessFromFileURLs(true); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setBlockNetworkImage(false); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } // Fixes broken full-screen modals/galleries due to body height being 0. webView.setLayoutParams( new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } return webView; } @ReactProp(name = "javaScriptEnabled") public void setJavaScriptEnabled(WebView view, boolean enabled) { view.getSettings().setJavaScriptEnabled(enabled); } @ReactProp(name = "thirdPartyCookiesEnabled") public void setThirdPartyCookiesEnabled(WebView view, boolean enabled) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().setAcceptThirdPartyCookies(view, enabled); } } @ReactProp(name = "scalesPageToFit") public void setScalesPageToFit(WebView view, boolean enabled) { view.getSettings().setUseWideViewPort(!enabled); } @ReactProp(name = "domStorageEnabled") public void setDomStorageEnabled(WebView view, boolean enabled) { view.getSettings().setDomStorageEnabled(enabled); } @ReactProp(name = "userAgent") public void setUserAgent(WebView view, @Nullable String userAgent) { if (userAgent != null) { // TODO(8496850): Fix incorrect behavior when property is unset (uA == null) view.getSettings().setUserAgentString(userAgent); } } @ReactProp(name = "mediaPlaybackRequiresUserAction") public void setMediaPlaybackRequiresUserAction(WebView view, boolean requires) { view.getSettings().setMediaPlaybackRequiresUserGesture(requires); } @ReactProp(name = "allowUniversalAccessFromFileURLs") public void setAllowUniversalAccessFromFileURLs(WebView view, boolean allow) { view.getSettings().setAllowUniversalAccessFromFileURLs(allow); } @ReactProp(name = "saveFormDataDisabled") public void setSaveFormDataDisabled(WebView view, boolean disable) { view.getSettings().setSaveFormData(!disable); } @ReactProp(name = "injectedJavaScript") public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScript) { ((ReactWebView) view).setInjectedJavaScript(injectedJavaScript); } @ReactProp(name = "messagingEnabled") public void setMessagingEnabled(WebView view, boolean enabled) { ((ReactWebView) view).setMessagingEnabled(enabled); } @ReactProp(name = "source") public void setSource(WebView view, @Nullable ReadableMap source) { if (source != null) { if (source.hasKey("html")) { String html = source.getString("html"); if (source.hasKey("baseUrl")) { view.loadDataWithBaseURL( source.getString("baseUrl"), html, HTML_MIME_TYPE, HTML_ENCODING, null); } else { view.loadData(html, HTML_MIME_TYPE, HTML_ENCODING); } return; } if (source.hasKey("uri")) { String url = source.getString("uri"); String previousUrl = view.getUrl(); if (previousUrl != null && previousUrl.equals(url)) { return; } if (source.hasKey("method")) { String method = source.getString("method"); if (method.equals(HTTP_METHOD_POST)) { byte[] postData = null; if (source.hasKey("body")) { String body = source.getString("body"); try { postData = body.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { postData = body.getBytes(); } } if (postData == null) { postData = new byte[0]; } view.postUrl(url, postData); return; } } HashMap headerMap = new HashMap<>(); if (source.hasKey("headers")) { ReadableMap headers = source.getMap("headers"); ReadableMapKeySetIterator iter = headers.keySetIterator(); while (iter.hasNextKey()) { String key = iter.nextKey(); if ("user-agent".equals(key.toLowerCase(Locale.ENGLISH))) { if (view.getSettings() != null) { view.getSettings().setUserAgentString(headers.getString(key)); } } else { headerMap.put(key, headers.getString(key)); } } } view.loadUrl(url, headerMap); return; } } view.loadUrl(BLANK_URL); } @ReactProp(name = "onContentSizeChange") public void setOnContentSizeChange(WebView view, boolean sendContentSizeChangeEvents) { if (sendContentSizeChangeEvents) { view.setPictureListener(getPictureListener()); } else { view.setPictureListener(null); } } @ReactProp(name = "mixedContentMode") public void setMixedContentMode(WebView view, @Nullable String mixedContentMode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (mixedContentMode == null || "never".equals(mixedContentMode)) { view.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW); } else if ("always".equals(mixedContentMode)) { view.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } else if ("compatibility".equals(mixedContentMode)) { view.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); } } } @ReactProp(name = "urlPrefixesForDefaultIntent") public void setUrlPrefixesForDefaultIntent( WebView view, @Nullable ReadableArray urlPrefixesForDefaultIntent) { ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient(); if (client != null && urlPrefixesForDefaultIntent != null) { client.setUrlPrefixesForDefaultIntent(urlPrefixesForDefaultIntent); } } @Override protected void addEventEmitters(ThemedReactContext reactContext, WebView view) { this.reactContext = reactContext; // Do not register default touch emitter and let WebView implementation handle touches view.setWebViewClient(new ReactWebViewClient()); } @Override public @Nullable Map getCommandsMap() { return MapBuilder.of( "goBack", COMMAND_GO_BACK, "goForward", COMMAND_GO_FORWARD, "reload", COMMAND_RELOAD, "stopLoading", COMMAND_STOP_LOADING, "postMessage", COMMAND_POST_MESSAGE, "injectJavaScript", COMMAND_INJECT_JAVASCRIPT ); } @Override public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray args) { switch (commandId) { case COMMAND_GO_BACK: root.goBack(); break; case COMMAND_GO_FORWARD: root.goForward(); break; case COMMAND_RELOAD: root.reload(); break; case COMMAND_STOP_LOADING: root.stopLoading(); break; case COMMAND_POST_MESSAGE: try { JSONObject eventInitDict = new JSONObject(); eventInitDict.put("data", args.getString(0)); root.loadUrl("javascript:(function () {" + "var event;" + "var data = " + eventInitDict.toString() + ";" + "try {" + "event = new MessageEvent('message', data);" + "} catch (e) {" + "event = document.createEvent('MessageEvent');" + "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + "}" + "document.dispatchEvent(event);" + "})();"); } catch (JSONException e) { throw new RuntimeException(e); } break; case COMMAND_INJECT_JAVASCRIPT: root.loadUrl("javascript:" + args.getString(0)); break; } } @Override public void onDropViewInstance(WebView webView) { super.onDropViewInstance(webView); ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener((ReactWebView) webView); ((ReactWebView) webView).cleanupCallbacksAndDestroy(); } protected WebView.PictureListener getPictureListener() { if (mPictureListener == null) { mPictureListener = new WebView.PictureListener() { @Override public void onNewPicture(WebView webView, Picture picture) { dispatchEvent( webView, new ContentSizeChangeEvent( webView.getId(), webView.getWidth(), webView.getContentHeight())); } }; } return mPictureListener; } protected static void dispatchEvent(WebView webView, Event event) { ReactContext reactContext = (ReactContext) webView.getContext(); EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); eventDispatcher.dispatchEvent(event); }}

  • react-native-fetch-blob
    • RNFetchBlobReq


      RN集成自签名https及双向认证-android(2)_第6张图片 RNFetchBlobReq.png
    • RNFetchBlob


      RN集成自签名https及双向认证-android(2)_第7张图片 RNFetchBlob.png
package com.RNFetchBlob;import android.app.Activity;import android.app.DownloadManager;import android.content.Intent;import android.net.Uri;import com.facebook.react.bridge.ActivityEventListener;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.LifecycleEventListener;import com.facebook.react.bridge.Promise;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableArray;import com.facebook.react.bridge.ReadableMap;// Cookiesimport com.facebook.react.bridge.WritableMap;import com.facebook.react.modules.network.ForwardingCookieHandler;import com.facebook.react.modules.network.CookieJarContainer;import com.facebook.react.modules.network.OkHttpClientProvider;import com.facebook.react.modules.network.ReactCookieJarContainer;import okhttp3.OkHttpClient;import okhttp3.JavaNetCookieJar;import java.io.IOException;import java.io.InputStream;import java.security.KeyStore;import java.security.SecureRandom;import java.security.cert.CertificateFactory;import java.util.HashMap;import java.util.Map;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.KeyManagerFactory;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSession;import javax.net.ssl.TrustManagerFactory;import static android.app.Activity.RESULT_OK;import static com.RNFetchBlob.RNFetchBlobConst.GET_CONTENT_INTENT;public class RNFetchBlob extends ReactContextBaseJavaModule {    // Cookies    private final ForwardingCookieHandler mCookieHandler;    private final CookieJarContainer mCookieJarContainer;    private final OkHttpClient mClient;    static ReactApplicationContext RCTContext;    static LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>();    static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);    static LinkedBlockingQueue fsTaskQueue = new LinkedBlockingQueue<>();    static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);    static public boolean ActionViewVisible = false;    static HashMap promiseTable = new HashMap<>();     //https --修改 --    public OkHttpClient initCustomOkHttpClient() {        OkHttpClient.Builder client = new OkHttpClient.Builder()                .connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .readTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .writeTimeout(30 * 1000, TimeUnit.MILLISECONDS)                .cookieJar(new ReactCookieJarContainer());//        client.addNetworkInterceptor(new StethoInterceptor());//        client.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));        try {            //你的证书文件,放在android的assets文件夹下            setCertificates(client, RCTContext.getAssets().open("CNPCCA.cer"));            client.hostnameVerifier(new HostnameVerifier() {                @Override                public boolean verify(String hostname, SSLSession session) {                    return true;                }            });        } catch (IOException e) {            e.printStackTrace();        }        OkHttpClient.Builder builder = OkHttpClientProvider.enableTls12OnPreLollipop(client);        return builder.build();    }    public void setCertificates(OkHttpClient.Builder client, InputStream... certificates) {        try {            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());            keyStore.load(null);            int index = 0;            for (InputStream certificate : certificates) {                String certificateAlias = Integer.toString(index++);                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));                try {                    if (certificate != null)                        certificate.close();                } catch (IOException e) {                }            }            SSLContext sslContext = SSLContext.getInstance("TLS");            TrustManagerFactory trustManagerFactory =                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());            trustManagerFactory.init(keyStore);            //初始化keystore            KeyStore clientKeyStore = KeyStore.getInstance("BKS");            clientKeyStore.load(RCTContext.getAssets().open("client.bks"), "mima".toCharArray());            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());            keyManagerFactory.init(clientKeyStore, "mima".toCharArray());            sslContext.init(                    keyManagerFactory.getKeyManagers(),                    trustManagerFactory.getTrustManagers(),                    new SecureRandom()            );            client.sslSocketFactory(sslContext.getSocketFactory());        } catch (Exception e) {            e.printStackTrace();        }    }            //https --修改 --    public RNFetchBlob(ReactApplicationContext reactContext) {        super(reactContext);        RCTContext = reactContext;        mClient = initCustomOkHttpClient();        mCookieHandler = new ForwardingCookieHandler(reactContext);        mCookieJarContainer = (CookieJarContainer) mClient.cookieJar();        mCookieJarContainer.setCookieJar(new JavaNetCookieJar(mCookieHandler));        reactContext.addActivityEventListener(new ActivityEventListener() {            @Override            public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {                if(requestCode == GET_CONTENT_INTENT && resultCode == RESULT_OK) {                    Uri d = data.getData();                    promiseTable.get(GET_CONTENT_INTENT).resolve(d.toString());                    promiseTable.remove(GET_CONTENT_INTENT);                }            }            @Override            public void onNewIntent(Intent intent) {            }        });    }    @Override    public String getName() {        return "RNFetchBlob";    }    @Override    public Map getConstants() {        return RNFetchBlobFS.getSystemfolders(this.getReactApplicationContext());    }    @ReactMethod    public void createFile(final String path, final String content, final String encode, final Callback callback) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.createFile(path, content, encode, callback);            }        });    }    @ReactMethod    public void actionViewIntent(String path, String mime, final Promise promise) {        try {            Intent intent= new Intent(Intent.ACTION_VIEW)                    .setDataAndType(Uri.parse("file://" + path), mime);            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            this.getReactApplicationContext().startActivity(intent);            ActionViewVisible = true;            final LifecycleEventListener listener = new LifecycleEventListener() {                @Override                public void onHostResume() {                    if(ActionViewVisible)                        promise.resolve(null);                    RCTContext.removeLifecycleEventListener(this);                }                @Override                public void onHostPause() {                }                @Override                public void onHostDestroy() {                }            };            RCTContext.addLifecycleEventListener(listener);        } catch(Exception ex) {            promise.reject(ex.getLocalizedMessage());        }    }    @ReactMethod    public void createFileASCII(final String path, final ReadableArray dataArray, final Callback callback) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.createFileASCII(path, dataArray, callback);            }        });    }    @ReactMethod    public void writeArrayChunk(final String streamId, final ReadableArray dataArray, final Callback callback) {        RNFetchBlobFS.writeArrayChunk(streamId, dataArray, callback);    }    @ReactMethod    public void unlink(String path, Callback callback) {        RNFetchBlobFS.unlink(path, callback);    }    @ReactMethod    public void mkdir(String path, Callback callback) {        RNFetchBlobFS.mkdir(path, callback);    }    @ReactMethod    public void exists(String path, Callback callback) {        RNFetchBlobFS.exists(path, callback);    }    @ReactMethod    public void cp(final String path, final String dest, final Callback callback) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.cp(path, dest, callback);            }        });    }    @ReactMethod    public void mv(String path, String dest, Callback callback) {        RNFetchBlobFS.mv(path, dest, callback);    }    @ReactMethod    public void ls(String path, Callback callback) {        RNFetchBlobFS.ls(path, callback);    }    @ReactMethod    public void writeStream(String path, String encode, boolean append, Callback callback) {        new RNFetchBlobFS(this.getReactApplicationContext()).writeStream(path, encode, append, callback);    }    @ReactMethod    public void writeChunk(String streamId, String data, Callback callback) {        RNFetchBlobFS.writeChunk(streamId, data, callback);    }    @ReactMethod    public void closeStream(String streamId, Callback callback) {        RNFetchBlobFS.closeStream(streamId, callback);    }    @ReactMethod    public void removeSession(ReadableArray paths, Callback callback) {        RNFetchBlobFS.removeSession(paths, callback);    }    @ReactMethod    public void readFile(final String path, final String encoding, final Promise promise) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.readFile(path, encoding, promise);            }        });    }    @ReactMethod    public void writeFileArray(final String path, final ReadableArray data, final boolean append, final Promise promise) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.writeFile(path, data, append, promise);            }        });    }    @ReactMethod    public void writeFile(final String path, final String encoding, final String data, final boolean append, final Promise promise) {        threadPool.execute(new Runnable() {            @Override            public void run() {                RNFetchBlobFS.writeFile(path, encoding, data, append, promise);            }        });    }    @ReactMethod    public void lstat(String path, Callback callback) {        RNFetchBlobFS.lstat(path, callback);    }    @ReactMethod    public void stat(String path, Callback callback) {        RNFetchBlobFS.stat(path, callback);    }    @ReactMethod    public void scanFile(final ReadableArray pairs, final Callback callback) {        final ReactApplicationContext ctx = this.getReactApplicationContext();        threadPool.execute(new Runnable() {            @Override            public void run() {                int size = pairs.size();                String [] p = new String[size];                String [] m = new String[size];                for(int i=0;i

原理就是,import我们copy改动的类,不再使用.jar包里的类,option+return自动import包路径
具体查看管知汇,前期管理

更多相关文章

  1. Android 根文件系统启动过程。
  2. android 下载网络pdf文件后并显示
  3. Android 上传头像(文件)到服务器
  4. Android代码混淆配置(Proguard文件解析)
  5. 升级Android SDK后ADT找不到adb.exe文件的解决办法
  6. 认识Android中的双向绑定
  7. android 文件系统分析
  8. Android 之6.0 双向通话自动录音
  9. android下解析xml文件遇到中文问题

随机推荐

  1. Android属性系统
  2. android 4.4 设置默认日期格式
  3. Android监听来电和去电的实现方法
  4. Android(安卓)JsBridge 源码解析
  5. listview使用小技巧
  6. ROS与Android的通信
  7. Android(安卓)SDK下载地址
  8. Android初级教程小案例之单选框RadioGrou
  9. Android(安卓)登录界面Demo源码
  10. java/android 统计文件夹大小及删除文件