美文网首页
Android 系统应用使用webview 报错

Android 系统应用使用webview 报错

作者: Battery_fc | 来源:发表于2019-04-24 22:17 被阅读0次

    我们在使用webview 的时候,当在主配置文件中配置了 android:sharedUserId="android.uid.system" 这个属性时,报以下错误

    E/AndroidRuntime(24145): Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
    E/AndroidRuntime(24145):        at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:100)
    E/AndroidRuntime(24145):        at android.webkit.WebView.getFactory(WebView.java:2194)
    E/AndroidRuntime(24145):        at android.webkit.WebView.ensureProviderCreated(WebView.java:2189)
    E/AndroidRuntime(24145):        at android.webkit.WebView.setOverScrollMode(WebView.java:2248)
    E/AndroidRuntime(24145):        at android.view.View.<init>(View.java:3617)
    E/AndroidRuntime(24145):        at android.view.View.<init>(View.java:3711)
    E/AndroidRuntime(24145):        at android.view.ViewGroup.<init>(ViewGroup.java:497)
    E/AndroidRuntime(24145):        at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:55)
    E/AndroidRuntime(24145):        at android.webkit.WebView.<init>(WebView.java:544)
    E/AndroidRuntime(24145):        at android.webkit.WebView.<init>(WebView.java:489)
    E/AndroidRuntime(24145):        at android.webkit.WebView.<init>(WebView.java:472)
    E/AndroidRuntime(24145):        at android.webkit.WebView.<init>(WebView.java:459)
    E/AndroidRuntime(24145):        at android.webkit.WebView.<init>(WebView.java:449)
    E/AndroidRuntime(24145):        at com.hzkj.system.usewebview.MainActivity.onCreate(MainActivity.java:18)
    E/AndroidRuntime(24145):        at android.app.Activity.performCreate(Activity.java:6222)
    E/AndroidRuntime(24145):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    E/AndroidRuntime(24145):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2295)
    E/AndroidRuntime(24145):        ... 10 more
    W/ActivityManagerService( 1013):   Force finishing activity 1 com.hzkj.system.usewebview/.MainActivity
    

    为何会抛出异常? 异常信息可以看出 是在 WebViewFactory.java 的getProvider 方法 抛出的。源码路径为
    frameworks/base/core/java/android/webkit/WebViewFactory.java

    static WebViewFactoryProvider getProvider() {
            synchronized (sProviderLock) {
                // For now the main purpose of this function (and the factory abstraction) is to keep
                // us honest and minimize usage of WebView internals when binding the proxy.
                if (sProviderInstance != null) return sProviderInstance; //如果sProviderInstance不为空直接返回
                
              //1,判断,如果是系统id ,则抛出异常。
                final int uid = android.os.Process.myUid();
                if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
                    throw new UnsupportedOperationException(
                            "For security reasons, WebView is not allowed in privileged processes");
                }
    
                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
                try {
                    //2
                    Class<WebViewFactoryProvider> providerClass = getProviderClass();
    
                    Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
                    try {
                        //3 给 sProviderInstance 赋值
                        sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
                                .newInstance(new WebViewDelegate());
                        if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                        return sProviderInstance;
                    } catch (Exception e) {
                        Log.e(LOGTAG, "error instantiating provider", e);
                        throw new AndroidRuntimeException(e);
                    } finally {
                        Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                    }
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                    StrictMode.setThreadPolicy(oldPolicy);
                }
            }
        }
    

    异常信息就是在注释1处抛出的,如果是系统id,就抛出异常。要解决该问题,绕开该条件判断就可以了。如果可以修改系统源码,去掉改判断,返回sProviderInstance 就可以。如何在不修改系统源码的前提下,在app端修改就解决这个问题呢?

    通过源码我们知道 ,当sProviderInstance 不为空时,是不会再执行下去的,直接返回sProviderInstance。那么我们可以通过反射,在调用webview 之前,给sProviderInstance 赋值,这样就可以了。

    注释3处就是 sProviderInstance 赋值的方式。 反射方法如下

    public static void hock(){
            int sdkVersion = Build.VERSION.SDK_INT;
            Log.d(TAG, "hock-->sdkVersion:"+sdkVersion);
            try {
        
                Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
                Field field = factoryClass.getDeclaredField("sProviderInstance");
                field.setAccessible(true);
                Object sProviderInstance = field.get(null);
                if (sProviderInstance!=null){
                    Log.d(TAG, "hock: sProviderInstance is not null");
                    return;
                }
    Method getProviderMethod = null;
                if(sdkVersion>22){
                    getProviderMethod = factoryClass.getDeclaredMethod("getProviderClass");
                }else if(sdkVersion==22){
                    getProviderMethod = factoryClass.getDeclaredMethod("getFactoryClass");
                }else {
                    Log.d(TAG, "hock: it is not need to hock webview!");
                    return;
                }
                getProviderMethod.setAccessible(true);
                Class<?> providerClass = (Class<?>) getProviderMethod.invoke(factoryClass);
                Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
                Constructor<?> providerConstructor = providerClass.getConstructor(delegateClass);
    if(providerConstructor!=null){
                    providerConstructor.setAccessible(true);
                    Constructor<?> constructor = delegateClass.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    sProviderInstance = providerConstructor.newInstance(constructor.newInstance());
                    Log.d(TAG, "hock--> sProviderInstance"+sProviderInstance);
                    field.set("sProviderInstance",sProviderInstance);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    

    在调用webview 之前,调用该方法就可以了。

    相关文章

      网友评论

          本文标题:Android 系统应用使用webview 报错

          本文链接:https://www.haomeiwen.com/subject/kzvggqtx.html