Android 基于Web Html实现webrtc 直播 调取Native操作

简介: Android 基于Web Html实现webrtc 直播 调取Native操作

Android 基于Web Html实现webrtc 直播 调取Native操作

选择控件


原生Webview

X5webView (腾讯内核)

XWalkView(因特尔浏览器内核-----已停止维护)

我的结果


原生Webview(失败)

X5webView (失败—但是使用QQ打开后可以使用)

XWalkView(成功----目前只是用在Android5.1.1、Android6.0.1两版本测试成功;在Android10.0上不知道是什么原因失败------会增加apk体积40M或者20M)下载链接

代码

权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission
        android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

a.引入依赖


//在app层级下build

   implementation 'org.xwalk:xwalk_core_library:23.53.589.4'

//在工程的build

       maven { url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'}

       //例如下面:

repositories {
        google()
        jcenter()
        maven { url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'}
    }
    allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'}
    }
}

引入上面的依赖必须要配置证书(如果技术强大,自己编译一个跳过证书的)

b.可以下载aar包,引入经过更改跳过证书验证的aar。下载链接


代码

xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WalkerXActivity">
    <org.xwalk.core.XWalkView
        android:id="@+id/xwalkView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity

package com.example.myapplication
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import org.xwalk.core.*
class WalkerXActivity : XWalkActivity() {
    private var webView: XWalkView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_wal2)
        webView = findViewById(R.id.xwalkView)
    }
    override fun onXWalkReady() {
        initSettings()
        webView?.setUIClient(XWUIClient(webView))
        webView?.setResourceClient(XWResourceClient(webView))
        //用来交互**加粗样式**
        //webView?.addJavascriptInterface(new AppShell(this), AppShell.TAG);
        webView?.loadUrl("http://www.baidu.com");
    }
    override fun onPointerCaptureChanged(hasCapture: Boolean) {}
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        if (isXWalkReady) webView?.onNewIntent(intent)
    }
    override fun onPause() {
        super.onPause()
        if (isXWalkReady) {
            webView?.pauseTimers()
            webView?.onHide()
        }
    }
    override fun onResume() {
        super.onResume()
        if (isXWalkReady) {
            webView?.resumeTimers()
            webView?.onShow()
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        if (isXWalkReady) {
            webView?.onDestroy()
        }
    }
    override fun onBackPressed() {
        if (isXWalkReady) {
            val history = webView?.navigationHistory
            if (history?.canGoBack()!!) {
                history.navigate(XWalkNavigationHistory.Direction.BACKWARD, 1)
            } else {
                super.onBackPressed()
            }
        } else {
            super.onBackPressed()
        }
    }
    /**
     * 没有允许定位的设置
     */
    @SuppressLint("SetJavaScriptEnabled")
    fun initSettings() {
        val webSettings = webView?.settings
        //启用JavaScript
        webSettings?.javaScriptEnabled = true
        //允许js弹窗alert等,window.open方法打开新的网页,默认不允许
        webSettings?.javaScriptCanOpenWindowsAutomatically = true
        //localStorage和sessionStorage
        webSettings?.domStorageEnabled = true
        //Web SQL Databases
        webSettings?.databaseEnabled = true
        //是否可访问Content Provider的资源,默认值 true
        webSettings?.allowContentAccess = true
        /*
        是否允许访问文件系统,默认值 true
        file:///androMSG_asset和file:///androMSG_res始终可以访问,不受其影响
         */webSettings?.allowFileAccess = true
        //是否允许通过file url加载的Javascript读取本地文件,默认值 false
        webSettings?.allowFileAccessFromFileURLs = true
        //是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
        webSettings?.allowUniversalAccessFromFileURLs = true
        //设置是否支持缩放
        webSettings?.setSupportZoom(false)
        //设置内置的缩放控件
        webSettings?.builtInZoomControls = false
        /*
         当该属性被设置为false时,加载页面的宽度总是适应WebView控件宽度;
         当被设置为true,当前页面包含viewport属性标签,在标签中指定宽度值生效,如果页面不包含viewport标签,无法提供一个宽度值,这个时候该方法将被使用。
         */webSettings?.useWideViewPort = false
        //缩放至屏幕大小
        webSettings?.loadWithOverviewMode = true
        //支持多窗口
        webSettings?.setSupportMultipleWindows(true)
        /*
        缓存模式
        LOAD_CACHE_ONLY         不使用网络,只读取本地缓存
        LOAD_DEFAULT            根据cache-control决定是否从网络上获取数据
        LOAD_NO_CACHE           不使用缓存,只从网络获取数据
        LOAD_CACHE_ELSE_NETWORK 只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
         */webSettings?.cacheMode = XWalkSettings.LOAD_DEFAULT
        //设置是否加载图片
        webSettings?.loadsImagesAutomatically = true
        //允许远程调试
        XWalkPreferences.setValue("enable-javascript", true)
        XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true)
    }
}

自定义XWalkUIClient

package com.example.myapplication
import android.graphics.Bitmap
import android.net.Uri
import android.os.Message
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.webkit.ValueCallback
import org.xwalk.core.CustomViewCallback
import org.xwalk.core.XWalkJavascriptResult
import org.xwalk.core.XWalkUIClient
import org.xwalk.core.XWalkView
class XWUIClient(view: XWalkView?) : XWalkUIClient(view) {
    override fun onPageLoadStarted(view: XWalkView, url: String) {
        Log.i(TAG, "onPageLoadStarted $url")
        super.onPageLoadStarted(view, url)
    }
    override fun onPageLoadStopped(
        view: XWalkView,
        url: String,
        status: LoadStatus
    ) {
        Log.i(
            TAG,
            "onPageLoadStopped $url, $status"
        )
        super.onPageLoadStopped(view, url, status)
    }
    override fun onJsAlert(
        view: XWalkView,
        url: String,
        message: String,
        result: XWalkJavascriptResult
    ): Boolean {
        Log.i(TAG, "onJsAlert $url, $message")
        return super.onJsAlert(view, url, message, result)
    }
    override fun onJsConfirm(
        view: XWalkView,
        url: String,
        message: String,
        result: XWalkJavascriptResult
    ): Boolean {
        Log.i(TAG, "onJsConfirm $url, $message")
        return super.onJsConfirm(view, url, message, result)
    }
    override fun onJsPrompt(
        view: XWalkView,
        url: String,
        message: String,
        defaultValue: String,
        result: XWalkJavascriptResult
    ): Boolean {
        Log.i(TAG, "onJsPrompt $url, $message")
        return super.onJsPrompt(view, url, message, defaultValue, result)
    }
    override fun onConsoleMessage(
        view: XWalkView,
        message: String,
        lineNumber: Int,
        sourceId: String,
        messageType: ConsoleMessageType
    ): Boolean {
        Log.i(
            TAG,
            "onConsoleMessage $message, $lineNumber, $sourceId, $messageType"
        )
        return super.onConsoleMessage(view, message, lineNumber, sourceId, messageType)
    }
    override fun onShowCustomView(
        view: View,
        requestedOrientation: Int,
        callback: CustomViewCallback
    ) {
        Log.i(TAG, "onShowCustomView $requestedOrientation")
        super.onShowCustomView(view, requestedOrientation, callback)
    }
    override fun onShowCustomView(
        view: View,
        callback: CustomViewCallback
    ) {
        Log.i(TAG, "onShowCustomView")
        super.onShowCustomView(view, callback)
    }
    override fun onCreateWindowRequested(
        view: XWalkView,
        initiator: InitiateBy,
        callback: ValueCallback<XWalkView>
    ): Boolean {
        Log.i(TAG, "onCreateWindowRequested")
        return super.onCreateWindowRequested(view, initiator, callback)
    }
    override fun onJavascriptModalDialog(
        view: XWalkView,
        type: JavascriptMessageType,
        url: String,
        message: String,
        defaultValue: String,
        result: XWalkJavascriptResult
    ): Boolean {
        Log.i(
            TAG,
            "onJavascriptModalDialog $type, $url, $message, $defaultValue"
        )
        return super.onJavascriptModalDialog(view, type, url, message, defaultValue, result)
    }
    override fun onFullscreenToggled(
        view: XWalkView,
        enterFullscreen: Boolean
    ) {
        Log.i(TAG, "onFullscreenToggled $enterFullscreen")
        super.onFullscreenToggled(view, enterFullscreen)
    }
    override fun onHideCustomView() {
        Log.i(TAG, "onHideCustomView")
        super.onHideCustomView()
    }
    override fun onIconAvailable(
        view: XWalkView,
        url: String,
        startDownload: Message
    ) {
        Log.i(
            TAG,
            "onIconAvailable $url, $startDownload"
        )
        super.onIconAvailable(view, url, startDownload)
    }
    override fun onJavascriptCloseWindow(view: XWalkView) {
        Log.i(TAG, "onJavascriptCloseWindow")
        super.onJavascriptCloseWindow(view)
    }
    override fun onReceivedIcon(
        view: XWalkView,
        url: String,
        icon: Bitmap
    ) {
        Log.i(TAG, "onReceivedIcon $url")
        super.onReceivedIcon(view, url, icon)
    }
    override fun onReceivedTitle(view: XWalkView, title: String) {
        Log.i(TAG, "onReceivedTitle $title")
        super.onReceivedTitle(view, title)
    }
    override fun onRequestFocus(view: XWalkView) {
        Log.i(TAG, "onRequestFocus")
        super.onRequestFocus(view)
    }
    override fun onScaleChanged(
        view: XWalkView,
        oldScale: Float,
        newScale: Float
    ) {
        Log.i(TAG, "onScaleChanged $oldScale, $newScale")
        super.onScaleChanged(view, oldScale, newScale)
    }
    override fun onUnhandledKeyEvent(
        view: XWalkView,
        event: KeyEvent
    ) {
        Log.i(
            TAG,
            "onUnhandledKeyEvent " + event.action + ", " + event.keyCode
        )
        super.onUnhandledKeyEvent(view, event)
    }
    override fun openFileChooser(
        view: XWalkView,
        uploadFile: ValueCallback<Uri>,
        acceptType: String,
        capture: String
    ) {
        Log.i(
            TAG,
            "openFileChooser $acceptType, $capture"
        )
        super.openFileChooser(view, uploadFile, acceptType, capture)
    }
    override fun shouldOverrideKeyEvent(
        view: XWalkView,
        event: KeyEvent
    ): Boolean {
        Log.i(
            TAG,
            "shouldOverrideKeyEvent " + event.action + ", " + event.keyCode
        )
        return super.shouldOverrideKeyEvent(view, event)
    }
    override fun getBridge(): Any {
        val obj = super.getBridge()
        if (obj != null) {
            Log.i(
                TAG,
                "getBridge " + obj.javaClass.simpleName
            )
        } else {
            Log.i(TAG, "getBridge()")
        }
        return obj
    }
    companion object {
        private const val TAG = "XWalkUIClient"
    }
}

自定义XWResourceClient


package com.example.myapplication;
import android.net.http.SslError;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebResourceResponse;
import org.json.JSONObject;
import org.xwalk.core.ClientCertRequest;
import org.xwalk.core.XWalkHttpAuthHandler;
import org.xwalk.core.XWalkResourceClient;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebResourceRequest;
import org.xwalk.core.XWalkWebResourceResponse;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Map;
public class XWResourceClient extends XWalkResourceClient {
    private static final String TAG = "XWalkUIClient";
    public XWResourceClient(XWalkView view) {
        super(view);
    }
    @Override
    public void onLoadStarted(XWalkView view, String url) {
        Log.i(TAG, "onLoadStarted " + url);
        super.onLoadStarted(view, url);
    }
    @Override
    public void onLoadFinished(XWalkView view, String url) {
        Log.i(TAG, "onLoadFinished " + url);
        super.onLoadFinished(view, url);
    }
    @Override
    public void onProgressChanged(XWalkView view, int progressInPercent) {
        Log.i(TAG, "onProgressChanged " + progressInPercent);
        super.onProgressChanged(view, progressInPercent);
    }
    @Override
    public boolean shouldOverrideUrlLoading(XWalkView view, String url) {
        Log.i(TAG, "shouldOverrideUrlLoading " + url);
        return super.shouldOverrideUrlLoading(view, url);
    }
    @Override
    public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
        Log.i(TAG, "shouldInterceptLoadRequest " + url);
        return super.shouldInterceptLoadRequest(view, url);
    }
    @Override
    public XWalkWebResourceResponse shouldInterceptLoadRequest(XWalkView view, XWalkWebResourceRequest request) {
        Log.i(TAG, "shouldInterceptLoadRequest " + request.isForMainFrame() + ", " + request.getUrl() + ", " + new JSONObject(request.getRequestHeaders()).toString());
        return super.shouldInterceptLoadRequest(view, request);
    }
    @Override
    public void onReceivedSslError(XWalkView view, ValueCallback<Boolean> callback, SslError error) {
        Log.i(TAG, "onReceivedSslError " + error.toString());
        callback.onReceiveValue(true);
    }
    @Override
    public void onReceivedLoadError(XWalkView view, int errorCode, String description, String failingUrl) {
        Log.i(TAG, "onReceivedLoadError " + errorCode + ", " + description + ", " + failingUrl);
        super.onReceivedLoadError(view, errorCode, description, failingUrl);
    }
    @Override
    public void onDocumentLoadedInFrame(XWalkView view, long frameId) {
        Log.i(TAG, "onDocumentLoadedInFrame " + frameId);
        super.onDocumentLoadedInFrame(view, frameId);
    }
    @Override
    public void onReceivedClientCertRequest(XWalkView view, ClientCertRequest handler) {
        Log.i(TAG, "onReceivedClientCertRequest " + handler.getHost() + ", " + handler.getPort() + ", " + Arrays.toString(handler.getKeyTypes()));
        super.onReceivedClientCertRequest(view, handler);
//        handler.proceed();
    }
    @Override
    public void onReceivedHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm) {
        Log.i(TAG, "onReceivedHttpAuthRequest " + host + ", " + realm);
        super.onReceivedHttpAuthRequest(view, handler, host, realm);
    }
    @Override
    public void onReceivedResponseHeaders(XWalkView view, XWalkWebResourceRequest request, XWalkWebResourceResponse response) {
        Log.i(TAG, "onReceivedResponseHeaders " + request.isForMainFrame() + ", " + request.getUrl() + ", " + new JSONObject(request.getRequestHeaders()).toString());
        super.onReceivedResponseHeaders(view, request, response);
    }
    @Override
    public XWalkWebResourceResponse createXWalkWebResourceResponse(String mimeType, String encoding, InputStream data) {
        Log.i(TAG, "createXWalkWebResourceResponse " + mimeType + ", " + encoding);
        return super.createXWalkWebResourceResponse(mimeType, encoding, data);
    }
    @Override
    public XWalkWebResourceResponse createXWalkWebResourceResponse(String mimeType, String encoding,
                                                                   InputStream data, int statusCode,
                                                                   String reasonPhrase, Map<String, String> responseHeaders) {
        Log.i(TAG, "createXWalkWebResourceResponse " + mimeType + ", " + encoding + ", " + statusCode + ", " + reasonPhrase + ", " + new JSONObject(responseHeaders));
        return super.createXWalkWebResourceResponse(mimeType, encoding, data, statusCode, reasonPhrase, responseHeaders);
    }
    @Override
    public void doUpdateVisitedHistory(XWalkView view, String url, boolean isReload) {
        Log.i(TAG, "doUpdateVisitedHistory " + url + ", " + isReload);
        super.doUpdateVisitedHistory(view, url, isReload);
    }
    @Override
    protected Object getBridge() {
        Object obj = super.getBridge();
        if (obj != null) {
            Log.i(TAG, "getBridge " + obj.getClass().getSimpleName());
        } else {
            Log.i(TAG, "getBridge()");
        }
        return obj;
    }
}
目录
相关文章
|
12天前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
12天前
|
Java Android开发
Android系统 获取用户最后操作时间回调实现和原理分析
Android系统 获取用户最后操作时间回调实现和原理分析
31 0
|
12天前
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
18 0
|
11天前
|
Android开发
Android WindowFeature小探究,Android客户端Web页面通用性能优化实践
Android WindowFeature小探究,Android客户端Web页面通用性能优化实践
|
12天前
|
JSON Android开发 数据格式
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
25 2
|
12天前
|
关系型数据库 MySQL
web简易开发(二){html5+php实现文件上传及通过关键字搜索已上传图片)}
web简易开发(二){html5+php实现文件上传及通过关键字搜索已上传图片)}
|
6天前
|
存储 JavaScript 前端开发
HTML web存储
HTML web存储
11 0
|
10天前
|
Web App开发 JavaScript Android开发
webRTC(十五),2024最新Android中级面试题目汇总解答
webRTC(十五),2024最新Android中级面试题目汇总解答
|
12天前
|
JavaScript 前端开发 UED
【Web 前端】如何将一个 HTML 元素添加到 DOM 树中的?
【5月更文挑战第2天】【Web 前端】如何将一个 HTML 元素添加到 DOM 树中的?
|
12天前
|
存储 前端开发 JavaScript
【Web 前端】如何找到所有 HTML select 标签的选中项?
【5月更文挑战第2天】【Web 前端】如何找到所有 HTML select 标签的选中项?