前言

简单记录下一下Android 应用内部打开网页的几种方式,方便自己查阅。

内容来自AI助手

正文

方式1

使用内置浏览器。

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.biumall.com"));
startActivity(browserIntent);

如果设备至少需要一个浏览器,否则就会崩溃,主要看AndroidRuntime日志。下面是没有浏览器时的打印。

AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.biumall.browser, PID: 6782
AndroidRuntime: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://www.biumall.com/... }
AndroidRuntime:        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2007)
AndroidRuntime:        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1673)
AndroidRuntime:        at android.app.Activity.startActivityForResult(Activity.java:4586)
AndroidRuntime:        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:780)
AndroidRuntime:        at android.app.Activity.startActivityForResult(Activity.java:4544)
AndroidRuntime:        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:761)
AndroidRuntime:        at android.app.Activity.startActivity(Activity.java:4905)
AndroidRuntime:        at android.app.Activity.startActivity(Activity.java:4873)
AndroidRuntime:        at com.biumall.browser.MainActivity.useBrowser(MainActivity.java:115)
AndroidRuntime:        at com.biumall.browser.MainActivity.access$300(MainActivity.java:24)
AndroidRuntime:        at com.biumall.browser.MainActivity$1.handleMessage(MainActivity.java:43)
AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
AndroidRuntime:        at android.os.Looper.loop(Looper.java:193)
AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6691)
AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:982)
ActivityManager:   Force finishing activity com.biumall.browser/.MainActivity

方式2

使用WebView

<WebView
    android:id="@+id/main_wb_web_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
WebView webView =  findViewById(R.id.main_wb_web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("https://www.biumall.com");

Android 8.0开始,系统应用使用这个会崩溃,系统应用不让使用。

AndroidRuntime: Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
AndroidRuntime:        at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:235)
AndroidRuntime:        at android.webkit.WebView.getFactory(WebView.java:2681)
AndroidRuntime:        at android.webkit.WebView.ensureProviderCreated(WebView.java:2676)
AndroidRuntime:        at android.webkit.WebView.setOverScrollMode(WebView.java:2741)
AndroidRuntime:        at android.view.View.<init>(View.java:4807)
AndroidRuntime:        at android.view.View.<init>(View.java:4948)
AndroidRuntime:        at android.view.ViewGroup.<init>(ViewGroup.java:661)
AndroidRuntime:        at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:55)
AndroidRuntime:        at android.webkit.WebView.<init>(WebView.java:659)
AndroidRuntime:        at android.webkit.WebView.<init>(WebView.java:604)
AndroidRuntime:        at android.webkit.WebView.<init>(WebView.java:587)
AndroidRuntime:        at android.webkit.WebView.<init>(WebView.java:574)

AndroidManifest.xml中去掉

android:sharedUserId="android.uid.system"

如果不行去掉,就按照下面的方式进行hook。

根据参考文章整理的。当然如果有源码,也可以改源码(这后续有空写一下)。

@SuppressLint({"PrivateApi", "SoonBlockedPrivateApi", "DiscouragedPrivateApi"})
public void hookWebView() {
    int sdkInt = Build.VERSION.SDK_INT;
    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.i(TAG, "sProviderInstance isn't null");
            return;
        }
        Method getProviderClassMethod;
        if (sdkInt > 22) {
            getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
        } else if (sdkInt == 22) {
            getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
        } else {
            Log.i(TAG, "Don't need to Hook WebView");
            return;
        }
        getProviderClassMethod.setAccessible(true);
        Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
        Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
        Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor();
        delegateConstructor.setAccessible(true);
        if (null != factoryProviderClass) {
            if (sdkInt < 26) {//低于Android O版本
                Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass);
                providerConstructor.setAccessible(true);
                sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
            } else {
                Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
                chromiumMethodName.setAccessible(true);
                String chromiumMethodNameStr = (String) chromiumMethodName.get(null);
                if (chromiumMethodNameStr == null) {
                    chromiumMethodNameStr = "create";
                }
                Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
                sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
            }
        }
        if (sProviderInstance != null) {
            field.set("sProviderInstance", sProviderInstance);
            Log.i(TAG, "Hook success!");
        } else {
            Log.i(TAG, "Hook failed!");
        }
    } catch (Throwable e) {
        Log.w(TAG, e);
    }
}

在onCreate()中setContentView()之前调用即可

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //
    hookWebView();
    setContentView(R.layout.activity_main);
    Log.d(TAG, "onCreate: ");
}

这样私有应用中使用WebView就没啥问题了。

方式3

使用CustomTabsIntent,这个需要引入jar

implementation 'androidx.browser:browser:1.3.0'

使用方式就行

CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse("https://www.biumall.com"));

这个也是需要设备中至少有一个浏览器,要不然也会崩溃。

下面没有浏览器时崩溃日志打印;

AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.biumall.browser, PID: 13466
AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.biumall.browser/com.biumall.browser.MainActivity}: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://www.biumall.com/... (has extras) }
AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2925)
AndroidRuntime:        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3060)
AndroidRuntime:        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1820)
AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
AndroidRuntime:        at android.os.Looper.loop(Looper.java:193)
AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6691)
AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:982)
AndroidRuntime: Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://www.biumall.com/... (has extras) }
AndroidRuntime:        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2007)
AndroidRuntime:        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1673)
AndroidRuntime:        at android.app.Activity.startActivityForResult(Activity.java:4586)
AndroidRuntime:        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:780)
AndroidRuntime:        at android.app.Activity.startActivityForResult(Activity.java:4544)
AndroidRuntime:        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:761)
AndroidRuntime:        at android.app.Activity.startActivity(Activity.java:4905)
AndroidRuntime:        at androidx.core.content.ContextCompat$Api16Impl.startActivity(ContextCompat.java:978)
AndroidRuntime:        at androidx.core.content.ContextCompat.startActivity(ContextCompat.java:318)
AndroidRuntime:        at androidx.browser.customtabs.CustomTabsIntent.launchUrl(CustomTabsIntent.java:483)
AndroidRuntime:        at com.biumall.browser.MainActivity.useCustomTabsIntent(MainActivity.java:108)
AndroidRuntime:        at com.biumall.browser.MainActivity.onCreate(MainActivity.java:60)
AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:7136)
AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:7127)
AndroidRuntime:        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2905)
AndroidRuntime:        ... 11 more
ActivityManager:   Force finishing activity com.biumall.browser/.MainActivity

小结

从上面看

  1. 使用WebView最简单,也不需要依赖设备中的浏览器。

  2. CustomTabsIntent或startActivity都需要使用设备中的浏览器。

参考文章

  1. 通过百度AI和腾讯元宝查询并整理的。

  2. webViwe 报错 For security reasons, WebView is not allowed in privileged processes

相关文章

暂无评论

none
暂无评论...