微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

React Native 自定义 webview 在开发时防止 SSL 错误

如何解决React Native 自定义 webview 在开发时防止 SSL 错误

问题
尝试在 Android 上使用 react-native-webview 连接到我的本地开发服务器。
您可以使用 http://10.0.0.2 作为认网关来连接到模拟器上的本地机器。或者,我在手机上运行构建并连接到我机器的 IPV4 地址。
我需要 Crypto API,而该 API 仅在 HTTPS 上可用,这意味着我需要连接到 https://10.0.0.2
我没有使用自签名证书。

快速而肮脏的解决方
handler.proceed() 包的 onReceivedSslError 方法的第一行调用 com.reactnativecommunity.webview
虽然这可能有效,但它不是首选方式,因为它不受源代码控制,并且需要在每次进行发布构建或全新安装项目时将其删除

解决方
查看下面的答案
在开发版本上创建自定义 webview 以规避 SSL 错误(或任何其他 webview 方法)。

解决方法

我的解决方案

1. 创建仅用于调试的类 CustomWebviewManager.java
我们不希望我们的自定义 webview 管理器最终出现在发布版本中。

package nl.myapp;

import android.webkit.WebView;
import android.webkit.SslErrorHandler;
import android.net.http.SslError;

import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
import com.reactnativecommunity.webview.RNCWebViewManager;

@ReactModule(name = CustomWebViewManager.REACT_CLASS)
public class CustomWebViewManager extends RNCWebViewManager {
    protected static final String REACT_CLASS = "RNCCustomWebView"; // React native import name

    protected static class CustomWebviewClient extends RNCWebViewClient {
        @Override
        public void onReceivedSslError(WebView view,SslErrorHandler handler,SslError error){
            // Prevent SSL errors
            handler.proceed();
        }
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    @Override
    protected void addEventEmitters(ThemedReactContext reactContext,WebView view) {
        // Set our custom client as webview client
        view.setWebViewClient(new CustomWebviewClient());
    }
}

2. 创建一个新类来注册 React Packages MyappAppPackage.java
我们应该仅在调试模式下注册我们的调试类并作为 ViewManager
React Native 将在下一步注册我们的包后自动调用 createViewManagers
使用 BuildConfig.DEBUG 仅在调试版本中执行。
我们不能直接实例化我们的类,因为它会导致产品构建错误。这就是我们使用 Class.forName

package nl.myapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MyappAppPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        List<ViewManager> viewManagers = new ArrayList<>();

        if (BuildConfig.DEBUG) {
            // Add custom webview manager to circumvent SSL errors
            try {
                Class<ViewManager> c = (Class<ViewManager>) Class.forName("nl.myapp.CustomWebViewManager");
                viewManagers.add(c.newInstance());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

        return viewManagers;
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

3.注册我们的套餐

package nl.myapp;

import android.app.Application;

import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost =
        new ReactNativeHost(this) {
          @Override
          public boolean getUseDeveloperSupport() {
              return BuildConfig.DEBUG;
          }

          @Override
          protected List<ReactPackage> getPackages() {
              @SuppressWarnings("UnnecessaryLocalVariable")
              List<ReactPackage> packages = new PackageList(this).getPackages();

              packages.add(new MyappAppPackage());

              return packages;
          }

          @Override
          protected String getJSMainModuleName() {
              return "index";
          }
        };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    ...
}

4.最后在开发时使用我们的自定义 webview
把它放在单独的文件中,否则热重载将不起作用,因为requireNativeComponent会再次尝试注册ViewManager
src/components/native/RNCCustomWebView.js

import {requireNativeComponent} from 'react-native';

module.exports = requireNativeComponent('RNCCustomWebView');

src/components/webview.js

import React from 'react';
import { WebView } from 'react-native-webview';
import RNCCustomWebView from './native/RNCCustomWebView';

// ...

const renderWebView = () => {
  // ...

  const nativeConfig = {};
  if (__DEV__) { // __DEV__ is set by RN on debug builds
    // Set custom component to circumvent SSL errors
    nativeConfig.component = RNCCustomWebView;
  }

  return (
    <WebView
      nativeConfig={nativeConfig}
      source="https://10.0.0.1"
    />
  );
};

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