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月前
|
JSON 前端开发 JavaScript
|
4月前
|
移动开发 JavaScript Java
关于Android中如何过滤HTML标签
关于Android中如何过滤HTML标签
57 0
|
25天前
|
Web App开发 Android开发
利用firefox调试安卓手机端web
该教程详细介绍如何通过Firefox浏览器实现手机与电脑的远程调试。手机端需安装最新版Firefox,并按指定步骤设置完成;电脑端则需安装15版及以上Firefox。设置完成后,通过工具栏中的“远程调试”选项,输入手机IP地址即可连接。连接确认后,即可使用电脑端Firefox调试器调试手机上的Web信息。注意,调试前手机需提前打开目标网页。
41 2
|
2月前
|
前端开发 程序员
【前端web入门第二天】01 html语法实现列表与表格_合并单元格
本文介绍了HTML中的列表与表格的使用方法。列表包括无序列表(`&lt;ul&gt;`嵌套`&lt;li&gt;`)、有序列表(`&lt;ol&gt;`嵌套`&lt;li&gt;`)和定义列表(`&lt;dl&gt;`嵌套`&lt;dt&gt;`和`&lt;dd&gt;`)。
58 19
|
2月前
|
前端开发 Windows
【前端web入门第一天】02 HTML图片标签 超链接标签 音频标签 视频标签
本文档详细介绍了HTML中的图片、超链接、音频和视频标签的使用方法。首先讲解了`&lt;img&gt;`标签的基本用法及其属性,包括如何使用相对路径和绝对路径。接着介绍了`&lt;a&gt;`标签,用于创建超链接,并展示了如何设置目标页面打开方式。最后,文档还涵盖了如何在网页中嵌入音频和视频文件,包括简化写法及常用属性。
46 13
|
2月前
|
前端开发 程序员 C++
【前端web入门第一天】01 开发环境、HTML基本语法文本标签
本文档详细介绍了HTML文本标签的基础知识。首先指导如何准备开发环境,包括安装VSCode及常用插件;接着全面解析HTML的基本结构与标签语法,涵盖从基本骨架搭建到注释的使用,以及标题、段落、换行和平行线、文本格式化等标签的具体应用,适合初学者循序渐进地掌握HTML。
|
3月前
|
移动开发 JavaScript 前端开发
揭秘!如何用Web2py+HTML5/CSS3/jQuery打造超炫响应式网站?你的设计梦想即将照进现实!
【8月更文挑战第31天】本文详细介绍如何利用Web2py框架及HTML5、CSS3与jQuery构建响应式网站。首先需安装Python和Web2py,并启动服务器。接着,在Web2py中创建新应用,例如命名为“ResponsiveSite”。随后,编写HTML5基本结构,包括头部、导航栏等元素。在`styles.css`文件中添加CSS3样式代码,实现响应式布局。最后,通过在`scripts.js`中加入jQuery脚本提升页面交互性,如点击导航项时平滑滚动至目标区域。此教程为你打下响应式网站设计的基础,便于进一步扩展和优化。
26 1
|
3月前
|
Dart 前端开发 Java
|
3月前
|
前端开发
HTML+CSS动画实现动感3D卡片墙:现代Web设计的视觉盛宴
HTML+CSS动画实现动感3D卡片墙:现代Web设计的视觉盛宴
|
3月前
|
XML JavaScript 测试技术
Web自动化测试框架(基础篇)--HTML页面元素和DOM对象
本文为Web自动化测试入门指南,介绍了HTML页面元素和DOM对象的基础知识,以及如何使用Python中的Selenium WebDriver进行元素定位、操作和等待机制,旨在帮助初学者理解Web自动化测试中的关键概念和操作技巧。
50 1