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;
    }
}
目录
相关文章
|
2月前
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
110 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
9月前
|
移动开发 JavaScript Java
关于Android中如何过滤HTML标签
关于Android中如何过滤HTML标签
89 0
|
10月前
|
文字识别 前端开发 API
视觉智能开放平台产品使用合集之需要在Web端处理本地文件并上传,该如何操作
视觉智能开放平台是指提供一系列基于视觉识别技术的API和服务的平台,这些服务通常包括图像识别、人脸识别、物体检测、文字识别、场景理解等。企业或开发者可以通过调用这些API,快速将视觉智能功能集成到自己的应用或服务中,而无需从零开始研发相关算法和技术。以下是一些常见的视觉智能开放平台产品及其应用场景的概览。
|
6月前
|
Web App开发 Android开发
利用firefox调试安卓手机端web
该教程详细介绍如何通过Firefox浏览器实现手机与电脑的远程调试。手机端需安装最新版Firefox,并按指定步骤设置完成;电脑端则需安装15版及以上Firefox。设置完成后,通过工具栏中的“远程调试”选项,输入手机IP地址即可连接。连接确认后,即可使用电脑端Firefox调试器调试手机上的Web信息。注意,调试前手机需提前打开目标网页。
244 2
|
7月前
|
Web App开发 网络协议 Android开发
Android平台一对一音视频通话方案大比拼:WebRTC VS RTMP VS RTSP,谁才是王者?
【9月更文挑战第4天】本文详细对比了在Android平台上实现一对一音视频通话时常用的WebRTC、RTMP及RTSP三种技术方案。从技术原理、性能表现与开发难度等方面进行了深入分析,并提供了示例代码。WebRTC适合追求低延迟和高质量的场景,但开发成本较高;RTMP和RTSP则在简化开发流程的同时仍能保持较好的传输效果,适用于不同需求的应用场景。
434 1
|
8月前
|
Android开发 iOS开发
[ionic]解决运行Android、IOS出现Could not find the web assets directory
[ionic]解决运行Android、IOS出现Could not find the web assets directory
82 1
|
8月前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
264 0
|
8月前
|
Web App开发 网络协议 Android开发
### 惊天对决!Android平台一对一音视频通话方案大比拼:WebRTC VS RTMP VS RTSP,谁才是王者?
【8月更文挑战第14天】随着移动互联网的发展,实时音视频通信已成为移动应用的关键部分。本文对比分析了Android平台上WebRTC、RTMP与RTSP三种主流技术方案。WebRTC提供端到端加密与直接数据传输,适于高质量低延迟通信;RTMP适用于直播场景,但需服务器中转;RTSP支持实时流播放,但在复杂网络下稳定性不及WebRTC。三种方案各有优劣,WebRTC功能强大但集成复杂,RTMP和RTSP实现较简单但需额外编码支持。本文还提供了示例代码以帮助开发者更好地理解和应用这些技术。
255 0
|
10月前
|
数据采集 Web App开发 前端开发
Selenium:自动化Web浏览器操作的强大工具
**Selenium** 是一款用于自动化Web应用测试和模拟用户行为的工具,支持多种浏览器和编程语言。安装包括安装Selenium库和对应浏览器的WebDriver。基本用法包括导入库、启动浏览器、查找与操作页面元素、等待元素加载及关闭浏览器。在实际项目中,Selenium常用于Web测试、爬虫、自动化表单填写等,优点是跨平台、模拟真实用户行为,但性能较低且依赖浏览器。
499 9
|
10月前
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。

热门文章

最新文章