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;
    }
}
目录
相关文章
|
3月前
|
存储 Web App开发 移动开发
HTML5 Web 存储详解
HTML5 Web存储提供了两种客户端数据存储机制:**Local Storage**和**Session Storage**。Local Storage用于长期存储数据,即使关闭浏览器数据也依然存在,适用于保存用户偏好设置等信息。Session Storage则在标签或窗口关闭时清除数据,适合存储临时信息。两者均提供了简单的API进行数据的存取操作,但需要注意的是,Web存储并非加密存储,不应存放敏感信息。现代浏览器普遍支持Web存储,合理利用这两种存储方式可提升Web应用的用户体验。
|
3月前
|
存储 移动开发 大数据
HTML5 Web IndexedDB 数据库详解
IndexedDB 是一种高效的浏览器存储方案,允许在本地存储大量结构化数据,支持索引和事务,适用于需要离线和大数据处理的应用。它由数据库、对象仓库等组成,通过键值对存储数据,确保数据一致性和完整性。本介绍展示了如何创建、读取、更新和删除数据,以及事务和错误处理的最佳实践。
|
2月前
|
前端开发 JavaScript 搜索推荐
HTML与CSS在Web组件化中的核心作用及前端技术趋势
本文探讨了HTML与CSS在Web组件化中的核心作用及前端技术趋势。从结构定义、语义化到样式封装与布局控制,两者不仅提升了代码复用率和可维护性,还通过响应式设计、动态样式等技术增强了用户体验。面对兼容性、代码复杂度等挑战,文章提出了相应的解决策略,强调了持续创新的重要性,旨在构建高效、灵活的Web应用。
46 6
|
2月前
|
前端开发 JavaScript UED
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势,包括样式表优化、DOM操作减少、图像优化等技术,并分析了电商网站的具体案例,强调了技术演进对Web性能的深远影响。
42 5
|
6月前
|
移动开发 JavaScript Java
关于Android中如何过滤HTML标签
关于Android中如何过滤HTML标签
69 0
|
3月前
|
存储 移动开发 数据库
HTML5 Web IndexedDB 数据库常用数据存储类型
IndexedDB 支持多种数据存储类型,满足复杂数据结构的存储需求。它包括基本数据类型(如 Number、String、Boolean、Date)、对象(简单和嵌套对象)、数组、Blob(用于二进制数据如图像和视频)、ArrayBuffer 和 Typed Arrays(处理二进制数据)、结构化克隆(支持 Map 和 Set 等复杂对象),以及 JSON 数据。尽管不直接支持非序列化数据(如函数和 DOM 节点),但可以通过转换实现存储。开发者应根据具体需求选择合适的数据类型,以优化性能和使用体验。
|
3月前
|
移动开发 JavaScript 前端开发
HTML5 Web Workers详解
HTML5 Web Workers 允许在后台线程中运行 JavaScript,实现复杂计算而不影响用户界面,提升应用性能。其主要特性包括并行处理、异步通信、独立作用域及多数据类型支持。通过创建和使用 Worker 文件,如 `worker.js`,可执行后台任务,并与主线程通过消息传递机制通信。适用于数据处理、图像处理、复杂计算及网络请求并行等场景。需要注意的是,Web Workers 在浏览器兼容性、安全性限制、调试及资源消耗方面需特别关注。合理利用 Web Workers 可显著增强 Web 应用的流畅度和响应速度。
|
3月前
|
SQL 存储 移动开发
HTML5 Web SQL 数据库详解
Web SQL 数据库是 HTML5 中的一种本地存储技术,允许在浏览器中使用 SQL 语言操作本地数据,支持离线访问和事务处理,适用于缓存数据和小型应用。然而,其存储容量有限且仅部分现代浏览器支持,标准已不再积极维护,未来可能被 IndexedDB 和 localStorage 等技术取代。使用时需谨慎考虑兼容性和发展前景。
|
3月前
|
存储 移动开发 缓存
HTML5 Web 存储详解
HTML5 Web 存储包括 `localStorage` 和 `sessionStorage`,前者提供持久存储且无过期时间,后者仅在会话期间有效。两者均支持键值对形式存储数据,容量约为 5-10 MB。`localStorage` 适用于用户偏好设置、登录状态保持及离线应用缓存;`sessionStorage` 则用于临时数据如表单输入。数据以字符串形式存储,可通过 `JSON` 方法处理对象。由于数据存储于本地,不适合存放敏感信息。示例代码展示了如何使用按钮将输入框内容保存至 `localStorage` 并进行清除操作。
|
3月前
|
移动开发 前端开发 JavaScript
HTML与现代Web开发的不同技术
【10月更文挑战第11天】HTML与现代Web开发的不同技术
41 0