WebView实现Demo记录

java 复制代码
package com.qisyun.sunday.activities;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;

import androidx.annotation.Nullable;

import com.qisyun.sunday.AlertDialog;
import com.qisyun.sunday.BaseActivity;
import com.qisyun.sunday.helper.BrowserEngineHelper;
import com.qisyun.sunday.qlog.XLog;
import com.qisyun.sunday.webview.BridgeHandler;
import com.qisyun.sunday.webview.IWebView;
import com.qisyun.sunday.webview.QsyBridge;
import com.qisyun.sunday.webview.WebPlayerFactory;
import com.qisyun.sunday.webview.WebViewClient;
import com.qisyun.sunday.webview.WebViewFactory;
import com.qisyun.sunday.webview.android.AndroidWebView;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class WebViewBaseActivity extends BaseActivity {
    // 静态字段
    private static final String TAG = "WebViewBaseActivity";
    private static final long TIMEOUT_LOADING;
    private static Map<String, String> keyMapper;

    // 实例字段
    private boolean backKeyHasDown;
    protected boolean initedWebEngine;
    private FrameLayout playerContainer;
    protected ViewGroup rootView;
    private Runnable timeoutTrigger;
    protected IWebView webView;
    private FrameLayout webViewContainer;

    // 静态初始化块
    static {
        TimeUnit timeUnit = TimeUnit.SECONDS;
        long seconds = 0x3c;
        TIMEOUT_LOADING = timeUnit.toMillis(seconds);
        Map<String, String> map = new HashMap<>();
        map.put(String.valueOf(0x15), "left");
        map.put(String.valueOf(0x16), "right");
        map.put(String.valueOf(0x13), "up");
        map.put(String.valueOf(0x14), "down");
        map.put(String.valueOf(0x17), "enter");
        map.put(String.valueOf(0x42), "");
        keyMapper = map;
    }

    // 构造函数
    public WebViewBaseActivity() {
        super();
        initedWebEngine = false;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 待实现的超时触发逻辑
            }
        };
        timeoutTrigger = runnable;
        backKeyHasDown = false;
    }

    // 私有方法:将按键事件分发到 JavaScript
    private void dispatchKey2Js(ValueCallback<Boolean> valueCallback, String keyCode) {
        IWebView webView = this.webView;
        if (webView == null) {
            valueCallback.onReceiveValue(Boolean.valueOf(false));
            return;
        }
        long currentTimeMillis = SystemClock.uptimeMillis();
        IWebView webView1 = this.webView;
        QsyBridge qsyBridge = webView1.getQsyBridge();
        String bridgeName = qsyBridge.getName();
        Object[] objects = new Object[4];
        objects[0] = bridgeName;
        objects[1] = Boolean.valueOf(true);
        objects[2] = Boolean.valueOf(true);
        objects[3] = keyCode;
        String format = String.format("%s && %s.onKeydown && %s.onKeydown('%s')", objects);
        webView.callJs(format, new ValueCallback() {
            @Override
            public void onReceiveValue(Object value) {
                // 待实现回调逻辑
            }
        });
    }

    // 私有方法:处理按键按下事件
    private void handleKeyDown(int keyCode) {
        Map<String, String> keyMap = keyMapper;
        String keyMapping = keyMap.get(String.valueOf(keyCode));
        if (TextUtils.isEmpty(keyMapping)) {
            return;
        }
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 待实现按键按下后的逻辑
            }
        };
        runOnUiThread(runnable);
    }

    // 私有方法:加载网页视图
    private void loadWebView() {
        if (initedWebEngine) {
            return;
        }
        initedWebEngine = true;
        onLoadEngine();
        getWindow().setBackgroundDrawableResource(0x7f05002a);
        boolean xWalkEnabled = BrowserEngineHelper.isXWalkEnabled();
        if (xWalkEnabled) {
            XLog.i(TAG, "xwalk enabled, start init.");
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    // 待实现 XWalk 初始化后的逻辑
                }
            };
            BrowserEngineHelper.initXwalk(this, runnable);
        } else {
            boolean x5Enabled = BrowserEngineHelper.isX5Enabled();
            if (x5Enabled) {
                XLog.i(TAG, "x5 enabled, start init.");
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        // 待实现 X5 初始化后的逻辑
                    }
                };
                BrowserEngineHelper.initX5(getApplicationContext(), runnable);
            } else {
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        // 待实现默认情况下的逻辑
                    }
                };
                runOnUiThread(runnable);
            }
        }
    }

    // 私有方法:显示 XWalk 加载错误对话框
    private AlertDialog showXWalkLoadErrorDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(0x7f0e005a);
        builder.setMessage(0x7f0e00c6);
        builder.setPositiveButton(0x7f0e0099, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 待实现正按钮点击逻辑
            }
        });
        builder.setNegativeButton(0x7f0e005c, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 待实现负按钮点击逻辑
            }
        });
        return builder.show();
    }

    // 受保护的虚拟方法:获取当前引擎名称
    protected String currentEngine() {
        IWebView webView = this.webView;
        if (webView == null) {
            return "";
        }
        if (webView instanceof AndroidWebView) {
            return "webview";
        } else {
            return "xwalk";
        }
    }

    // 受保护的虚拟方法:关闭设备码显示
    protected void dismissDeviceCode() {
        // 待实现关闭设备码显示的逻辑
    }

    // 受保护的虚拟方法:根据内容提供者获取用户名
    protected String getUserNameByContentProvider() {
        return "";
    }

    // 受保护的虚拟方法:返回上一页(通过回调实现)
    protected void goBack(ValueCallback<Boolean> valueCallback) {
        IWebView webView = this.webView;
        if (webView == null) {
            valueCallback.onReceiveValue(Boolean.valueOf(false));
            return;
        }
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                dispatchKey2Js(valueCallback, "back");
            }
        };
        dispatchKey2Js(valueCallback, "back");
    }

    // 受保护的虚拟方法:处理返回键按下
    protected void handleBackPressed() {
        // 待实现处理返回键按下的逻辑
    }

    // 受保护的虚拟方法:初始化网页视图
    protected IWebView initWebView() {
        IWebView webView = this.webView;
        if (webView!= null) {
            ViewGroup rootView = this.rootView;
            rootView.removeView(webView.getWebView());
        }
        FrameLayout playerContainer = this.playerContainer;
        if (playerContainer!= null) {
            WebPlayerFactory.disposeAllPlayer();
            playerContainer.removeAllViews();
        }
        FrameLayout webViewContainer = this.webViewContainer;
        if (webViewContainer!= null) {
            WebViewFactory.disposeAllWebView();
            webViewContainer.removeAllViews();
        }
        try {
            IWebView webView1 = BrowserEngineHelper.getCurrentBrowserEngine(getApplicationContext());
            this.webView = webView1;
            View webViewView = webView1.getWebView();
            webViewView.setBackgroundColor(0);
            BridgeHandler bridgeHandler = new BridgeHandler() {
                @Override
                public void handle(String action, Map<String, String> params) {
                    // 待实现桥接处理逻辑
                }
            };
            webView1.setBridgeHandler(bridgeHandler);
            webView1.setWebViewClient(new EvsWebViewClient(this, timeoutTrigger));
            rootView.addView(webViewView, -1, -1);
            boolean hardwareAccelerated = webViewView.isHardwareAccelerated();
            XLog.i(TAG, "isHardwareAccelerated ===> " + hardwareAccelerated);
            return webView1;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 受保护的虚拟方法:加载 URL
    protected void loadUrl(String url) {
        try {
            IWebView webView = this.webView;
            webView.loadData(url);
            onStartLoadUrl(url);
        } catch (Exception e) {
            e.printStackTrace();
            Runnable timeoutRunnable = timeoutTrigger;
            cancelRun(timeoutRunnable);
            Runnable runnable = timeoutTrigger;
            delayRunOnUiThread(runnable, TIMEOUT_LOADING);
        }
    }

    // 受保护的虚拟方法:活动结果处理
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.onActivityResult(requestCode, resultCode, data);
        }
    }

    // 受保护的虚拟方法:浏览器准备就绪时的处理
    protected void onBrowserReady() {
        // 待实现浏览器准备就绪的逻辑
    }

    // 受保护的虚拟方法:创建活动时的处理
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // 受保护的虚拟方法:销毁活动时的处理
    protected void onDestroy() {
        super.onDestroy();
        WebPlayerFactory.disposeAllPlayer();
        FrameLayout playerContainer = this.playerContainer;
        if (playerContainer!= null) {
            playerContainer.removeAllViews();
        }
        WebViewFactory.disposeAllWebView();
        FrameLayout webViewContainer = this.webViewContainer;
        if (webViewContainer!= null) {
            webViewContainer.removeAllViews();
        }
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.onDestroy();
        }
    }

    // 受保护的虚拟方法:加载引擎时的处理
    protected void onLoadEngine() {
        // 待实现加载引擎的逻辑
    }

    // 受保护的虚拟方法:页面加载错误时的处理
    protected void onLoadPageError(AppWebResourceError error, String url) {
        // 待实现页面加载错误的逻辑
    }

    // 受保护的虚拟方法:页面加载完成时的处理
    protected void onLoadPageFinished(String url) {
        // 待实现页面加载完成的逻辑
    }

    // 受保护的虚拟方法:页面加载超时的处理
    protected void onLoadPageTimeout() {
        // 待实现页面加载超时的逻辑
    }

    // 受保护的虚拟方法:新意图处理
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.onNewIntent(intent);
        }
    }

    // 受保护的虚拟方法:恢复活动时的处理
    protected void onResume() {
        super.onResume();
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.onResume();
        }
    }

    // 受保护的虚拟方法:重试加载页面时的处理
    protected void onRetryLoadPage() {
        // 待实现重试加载页面的逻辑
    }

    // 受保护的虚拟方法:显示图片时的处理
    protected void onShowImage(String url, String title, String description) {
        // 待实现显示图片的逻辑
    }

    // 受保护的虚拟方法:显示跑马灯文本时的处理
    protected void onShowMarqueeText(String text, String title, String description) {
        // 待实现显示跑马灯文本的逻辑
    }

    // 受保护的虚拟方法:开始加载 URL 时的处理
    protected void onStartLoadUrl(String url) {
        // 待实现开始加载 URL 的逻辑
    }

    // 受保护的虚拟方法:停止活动时的处理
    protected void onStop() {
        super.onStop();
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.onPause();
        }
    }

    // 受保护的虚拟方法:重新加载页面
    protected void reloadPage() {
        removeAllOutViews();
        IWebView webView = this.webView;
        if (webView!= null) {
            webView.reload();
        }
    }

    // 受保护的虚拟方法:移除所有外部视图
    protected void removeAllOutViews() {
        try {
            WebPlayerFactory.disposeAllPlayer();
            FrameLayout playerContainer = this.playerContainer;
            playerContainer.removeAllViews();
            WebViewFactory.disposeAllWebView();
            FrameLayout webViewContainer = this.webViewContainer;
            webViewContainer.removeAllViews();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 受保护的虚拟方法:设置网页播放器容器
    protected void setWebPlayerContainer(FrameLayout frameLayout) {
        playerContainer = frameLayout;
    }

    // 受保护的虚拟方法:设置网页视图容器(根视图组)
    protected void setWebViewContainer(ViewGroup viewGroup) {
        rootView = viewGroup;
        loadWebView();
    }

    // 受保护的虚拟方法:设置网页视图组
    protected void setWebViewGroup(FrameLayout frameLayout) {
        webViewContainer = frameLayout;
    }

    // 受保护的虚拟方法:显示设备码
    protected void showDeviceCode(String code) {
        // 待实现显示设备码的逻辑
    }

    // 公共方法:分发按键事件
    public boolean dispatchKeyEvent(KeyEvent event) {
        FrameLayout playerContainer = this.playerContainer;
        if (playerContainer!= null) {
            int childCount = playerContainer.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = playerContainer.getChildAt(i);
                if (child.isFocusable()) {
                    boolean result = child.dispatchKeyEvent(event);
                    if (result) {
                        backKeyHasDown = true;
                        return true;
                    }
                }
            }
        }
        FrameLayout webViewContainer = this.webViewContainer;
        if (webViewContainer!= null) {
            int childCount = webViewContainer.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = webViewContainer.getChildAt(i);
                if (child.isFocusable()) {
                    boolean result = child.dispatchKeyEvent(event);
                    if (result) {
                        backKeyHasDown = true;
                        return true;
                    }
                }
            }
        }
        int action = event.getAction();
        if (action == KeyEvent.ACTION_DOWN) {
            backKeyHasDown = true;
            int keyCode = event.getKeyCode();
            if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == 0x42 || keyCode == 0x6f) {
                handleKeyDown(keyCode);
            } else {
                switch (keyCode) {
                    case 0x13:
                        handleKeyDown(keyCode);
                        break;
                    case 0x14:
                        handleKeyDown(keyCode);
                        break;
                    case 0x15:
                        handleKeyDown(keyCode);
                        break;
                    case 0x16:
                        handleKeyDown(keyCode);
                        break;
                    case 0x17:
                        handleKeyDown(keyCode);
                        break;
                }
            }
        } else if (action == KeyEvent.ACTION_UP && backKeyHasDown) {
            backKeyHasDown = false;
            int keyCode = event.getKeyCode();
        }
    } 
}

安卓WebViewProxy

java 复制代码
package com.qisyun.sunday.webview;

import android.content.Context;
import android.view.View;
import android.view.ViewParent;
import android.view.ViewGroup.LayoutParams;
import android.webkit.ValueCallback;

public class WebViewProxy implements IWebView {
    // 静态字段
    private static final String TAG = "WebViewProxy";

    // 实例字段
    private JSDelegate jsDelegate;
    private IWebView webView;

    // 构造方法
    public WebViewProxy(Context context) {
        webView = null;
        webView = new AndroidWebView(context, true);
        EvsWebViewClient webViewClient = new EvsWebViewClient(this, null);
        webView.setWebViewClient(webViewClient);
    }

    // 静态方法:回调方法
    static void access$100(WebViewProxy proxy, String methodName, Object[] args) {
        proxy.callback(methodName, args);
    }

    // 私有方法:可变参数回调方法
    private void callback(String methodName, Object[] args) {
        if (jsDelegate!= null) {
            jsDelegate.call(methodName, args);
        }
    }

    // 实现 IWebView 接口的方法:调用 JavaScript
    @Override
    public void callJs(String script, ValueCallback<String> callback) {
        webView.callJs(script, callback);
    }

    // 实现 IWebView 接口的方法:检查并返回上一页
    @Override
    public boolean checkAndGoBack() {
        return webView.checkAndGoBack();
    }

    // 实现 IWebView 接口的方法:获取布局参数
    @Override
    public LayoutParams getLayoutParams() {
        return webView.getLayoutParams();
    }

    // 实现 IWebView 接口的方法:获取父视图
    @Override
    public ViewParent getParentView() {
        return webView.getParentView();
    }

    // 实现 IWebView 接口的方法:获取 QsyBridge
    @Override
    public QsyBridge getQsyBridge() {
        return webView.getQsyBridge();
    }

    // 实现 IWebView 接口的方法:获取网页视图
    @Override
    public View getWebView() {
        return webView.getWebView();
    }

    // 实现 IWebView 接口的方法:获取网页视图 ID
    @Override
    public String getWebViewId() {
        return webView.getWebViewId();
    }

    // 实现 IWebView 接口的方法:加载数据
    @Override
    public void loadData(String data) {
        webView.loadData(data);
    }

    // 实现 IWebView 接口的方法:处理活动结果
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        webView.onActivityResult(requestCode, resultCode, data);
    }

    // 实现 IWebView 接口的方法:销毁
    @Override
    public void onDestroy() {
        webView.onDestroy();
    }

    // 实现 IWebView 接口的方法:处理新意图
    @Override
    public boolean onNewIntent(Intent intent) {
        return webView.onNewIntent(intent);
    }

    // 实现 IWebView 接口的方法:暂停
    @Override
    public void onPause() {
        webView.onPause();
    }

    // 实现 IWebView 接口的方法:恢复
    @Override
    public void onResume() {
        webView.onResume();
    }

    // 实现 IWebView 接口的方法:重新加载
    @Override
    public void reload() {
        webView.reload();
    }

    // 实现 IWebView 接口的方法:移除播放器视图
    @Override
    public void removePlayerView(IWebPlayer webPlayer) {
        webView.removePlayerView(webPlayer);
    }

    // 实现 IWebView 接口的方法:移除网页视图
    @Override
    public void removeWebView(IWebView webViewToRemove) {
        webView.removeWebView(webViewToRemove);
    }

    // 实现 IWebView 接口的方法:设置桥接处理器
    @Override
    public void setBridgeHandler(BridgeHandler bridgeHandler) {
        webView.setBridgeHandler(bridgeHandler);
    }

    // 实现 IWebView 接口的方法:设置 JavaScript 委托
    @Override
    public void setJsDelegate(JSDelegate jsDelegate) {
        this.jsDelegate = jsDelegate;
    }

    // 实现 IWebView 接口的方法:设置位置和大小
    @Override
    public void setPositionAndSize(int x, int y, int width, int height) {
        webView.setPositionAndSize(x, y, width, height);
    }

    // 实现 IWebView 接口的方法:设置网页视图客户端
    @Override
    public void setWebViewClient(WebViewClient webViewClient) {
        webView.setWebViewClient(webViewClient);
    }

    // 实现 IWebView 接口的方法:显示播放器视图
    @Override
    public void showPlayerView(IWebPlayer webPlayer) {
        webView.showPlayerView(webPlayer);
    }

    // 实现 IWebView 接口的方法:显示网页视图
    @Override
    public void showWebView(IWebView webViewToShow) {
        webView.showWebView(webViewToShow);
    }
}

安卓 WebView

java 复制代码
package com.qisyun.sunday.webview;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.ViewParent;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.qisyun.common.Utils;
import com.qisyun.plugin.core.IManager;
import com.qisyun.plugin.host.ManagerPluginLoader;

import java.lang.reflect.Method;

public class AndroidWebView extends WebView implements IWebView {
    // 实例字段
    private QsyBridge bridge;
    private WebViewClient delegateClient;
    private JSDelegate jsDelegate;
    private ZlzpPluginJsBridgeImpl pluginJsBridge;
    private Rect positionInfo;
    private String webviewId;

    // 构造方法
    public AndroidWebView(Context context) {
        this(context, false);
    }

    // 构造方法
    public AndroidWebView(Context context, boolean enableJsBridge) {
        this(context, null, enableJsBridge);
    }

    // 构造方法
    public AndroidWebView(Context context, AttributeSet attrs, boolean enableJsBridge) {
        super(context, attrs);
        initView(context, enableJsBridge);
        enableZlzpPluginJsBridge();
    }

    // 静态方法:获取委托客户端
    static WebViewClient access$000(AndroidWebView webView) {
        return webView.delegateClient;
    }

    // 私有方法:构建桥接对象
    private QsyBridge buildBridge(BridgeHandler bridgeHandler) {
        return new AndroidQsyBridge(bridgeHandler, this);
    }

    // 私有方法:启用 Zlzp 插件 JavaScript 桥接
    private void enableZlzpPluginJsBridge() {
        IManager pluginManager = ManagerPluginLoader.getInstance().getPluginManager();
        pluginJsBridge = new ZlzpPluginJsBridgeImpl(this, pluginManager);
        pluginJsBridge.enableJsBridge();
    }

    // 私有方法:获取 PC 端用户代理字符串
    private String getPCUa() {
        boolean isFollowSystemLanguage = LanguageHelper.isFollowSystemLanguage();
        if (!isFollowSystemLanguage) {
            String currentLanguageKey = LanguageHelper.getCurrentLanguageKey();
            if (currentLanguageKey!= null) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(" lang/").append(currentLanguageKey);
                return stringBuilder.toString();
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Mozilla/5.0 (Linux; x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36 zlzp/%s");
        Object[] args = new Object[2];
        args[0] = getWebviewVersion();
        args[1] = AppVersion.getVersionName();
        return String.format(stringBuilder.toString(), args);
    }

    // 私有方法:获取 WebView 版本号
    private String getWebviewVersion() {
        String systemWebViewVersion = AppVersion.getSystemWebViewVersion();
        if (!TextUtils.isEmpty(systemWebViewVersion)) {
            return systemWebViewVersion;
        } else {
            return "53.0.2785.143";
        }
    }

    // 私有方法:初始化视图
    private void initView(Context context, boolean enableJsBridge) {
        webviewId = Utils.randomId();
        setWebViewClient(new AndroidWebView$1(this));
        setWebChromeClient(new AndroidWebView$2(this, context));
        setHorizontalFadingEdgeEnabled(false);
        setVerticalFadingEdgeEnabled(false);
        setFadingEdgeLength(0);
        setOverScrollMode(2);
        setFocusable(true);
        setLayerType(0, null);
        if (Build.VERSION.SDK_INT >= 21) {
            setFocusedByDefault(true);
        }
        setFocusableInTouchMode(true);
        requestFocusFromTouch();
        setDrawingCacheEnabled(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            setWebContentsDebuggingEnabled(true);
        }
        WebSettings settings = getSettings();
        settings.setCacheMode(-1);
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        settings.setAllowFileAccess(true);
        settings.setDatabaseEnabled(true);
        settings.setLoadsImagesAutomatically(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
        settings.setPluginState(WebSettings.PluginState.ON);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            settings.setMediaPlaybackRequiresUserGesture(false);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            settings.setAllowFileAccessFromFileURLs(true);
            settings.setAllowUniversalAccessFromFileURLs(true);
        }
        settings.setLoadWithOverviewMode(true);
        settings.setUseWideViewPort(false);
        String userAgent = getPCUa();
        settings.setUserAgentString(userAgent);
        setInitialScale(100);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            CookieManager.getInstance().setAcceptThirdPartyCookies(this, true);
        }
    }

    // 实现 IWebView 接口的方法:调用 JavaScript
    @Override
    public void callJs(String script, ValueCallback<String> callback) {
        AndroidWebView$3 runnable = new AndroidWebView$3(this, script, callback);
        Looper myLooper = Looper.myLooper();
        Looper mainLooper = Looper.getMainLooper();
        if (myLooper == mainLooper) {
            runnable.run();
        } else {
            post(runnable);
        }
    }

    // 实现 IWebView 接口的方法:检查并返回上一页
    @Override
    public boolean checkAndGoBack() {
        if (canGoBack()) {
            goBack();
            return true;
        } else {
            return false;
        }
    }

    // 重写 dispatchKeyEvent 方法
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int keyCode = event.getKeyCode();
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (canGoBack() && event.getAction() == KeyEvent.ACTION_DOWN) {
                goBack();
                return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }

    // 实现 IWebView 接口的方法:获取布局参数
    @Override
    public LayoutParams getLayoutParams() {
        Rect positionInfo = this.positionInfo;
        if (positionInfo!= null) {
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(positionInfo.width(), positionInfo.height());
            layoutParams.leftMargin = positionInfo.left;
            layoutParams.topMargin = positionInfo.top;
            return layoutParams;
        } else {
            return super.getLayoutParams();
        }
    }

    // 实现 IWebView 接口的方法:获取父视图
    @Override
    public ViewParent getParentView() {
        return getParent();
    }

    // 实现 IWebView 接口的方法:获取 QsyBridge
    @Override
    public QsyBridge getQsyBridge() {
        return bridge;
    }

    // 实现 IWebView 接口的方法:获取网页视图
    @Override
    public View getWebView() {
        return this;
    }

    // 实现 IWebView 接口的方法:获取网页视图 ID
    @Override
    public String getWebViewId() {
        return webviewId;
    }

    // 实现 IWebView 接口的方法:加载数据
    @Override
    public void loadData(String data) {
        loadUrl(data);
    }

    // 实现 IWebView 接口的方法:原生播放器支持
    @Override
    public boolean nativePlayer() {
        return true;
    }

    // 实现 IWebView 接口的方法:处理活动结果
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 空实现
    }

    // 重写 onAttachedToWindow 方法
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        requestFocus();
        requestFocusFromTouch();
    }

    // 实现 IWebView 接口的方法:销毁
    @Override
    public void onDestroy() {
        super.onDetachedFromWindow();
    }

    // 实现 IWebView 接口的方法:处理新意图
    @Override
    public boolean onNewIntent(Intent intent) {
        return false;
    }

    // 实现 IWebView 接口的方法:暂停
    @Override
    public void onPause() {
        super.onPause();
        pauseTimers();
    }

    // 实现 IWebView 接口的方法:恢复
    @Override
    public void onResume() {
        super.onResume();
        resumeTimers();
    }

    // 实现 IWebView 接口的方法:重新加载
    @Override
    public void reload() {
        super.reload();
    }

    // 实现 IWebView 接口的方法:移除播放器视图
    @Override
    public void removePlayerView(IWebPlayer webPlayer) {
        WebViewClient delegateClient = this.delegateClient;
        if (delegateClient!= null) {
            delegateClient.removePlayerView(webPlayer);
        }
    }

    // 实现 IWebView 接口的方法:移除网页视图
    @Override
    public void removeWebView(IWebView webViewToRemove) {
        WebViewClient delegateClient = this.delegateClient;
        if (delegateClient!= null) {
            delegateClient.removeWebView(webViewToRemove);
        }
    }

    // 实现 IWebView 接口的方法:设置桥接处理器
    @Override
    public void setBridgeHandler(BridgeHandler bridgeHandler) {
        bridge = buildBridge(bridgeHandler);
        String bridgeName = bridge.getName();
        addJavascriptInterface(bridge, bridgeName);
    }

    // 实现 IWebView 接口的方法:设置 JavaScript 委托
    @Override
    public void setJsDelegate(JSDelegate jsDelegate) {
        this.jsDelegate = jsDelegate;
    }

    // 实现 IWebView 接口的方法:设置位置和大小
    @Override
    public void setPositionAndSize(int x, int y, int width, int height) {
        Rect positionInfo = this.positionInfo;
        if (positionInfo == null) {
            positionInfo = new Rect();
            this.positionInfo = positionInfo;
        }
        positionInfo.set(x, y, x + width, y + height);
    }

    // 实现 IWebView 接口的方法:设置网页视图客户端
    @Override
    public void setWebViewClient(WebViewClient webViewClient) {
        this.delegateClient = webViewClient;
    }

    // 实现 IWebView 接口的方法:显示播放器视图
    @Override
    public void showPlayerView(IWebPlayer webPlayer) {
        WebViewClient delegateClient = this.delegateClient;
        if (delegateClient!= null) {
            delegateClient.showPlayerView(webPlayer);
        }
    }

    // 实现 IWebView 接口的方法:显示网页视图
    @Override
    public void showWebView(IWebView webViewToShow) {
        WebViewClient delegateClient = this.delegateClient;
        if (delegateClient!= null) {
            delegateClient.showWebView(webViewToShow);
        }
    }
}

实现三方游览器

java 复制代码
package com.qisyun.sunday.webview;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.ViewParent;
import android.webkit.ValueCallback;

import org.json.JSONException;
import org.json.JSONObject;
import org.xwalk.core.XWalkNavigationHistory;
import org.xwalk.core.XWalkNavigationHistory.Direction;
import org.xwalk.core.XWalkPreferences;
import org.xwalk.core.XWalkResourceClient;
import org.xwalk.core.XWalkUIClient;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebViewBridge;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringBuilder;

public class XWalkWebView extends XWalkView implements IWebView {
    // 静态字段
    public static final String MANIFEST_ASSETS_PATH = "xwalk/manifest.json";
    public static final String TAG = "XWalkWebView";

    // 实例字段
    private QsyBridge bridge;
    private XWalkCookieManager cookieManager;
    private JSDelegate jsDelegate;
    private ZlzpPluginJsBridgeImpl pluginJsBridge;
    private Rect positionInfo;
    private WebViewClient webViewClient;
    private String webViewId;

    // 构造方法
    public XWalkWebView(Context context) {
        this(context, null);
    }

    // 构造方法
    public XWalkWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        positionInfo = null;
        initXWalk(context);
        enableZlzpPluginJsBridge();
    }

    // 静态方法:获取 WebViewClient
    static WebViewClient access$000(XWalkWebView webView) {
        return webView.webViewClient;
    }

    // 静态方法:获取 XWalkCookieManager
    static XWalkCookieManager access$100(XWalkWebView webView) {
        return webView.cookieManager;
    }

    // 私有方法:构建桥接对象
    private QsyBridge buildBridge(BridgeHandler bridgeHandler) {
        return new XwalkQsyBridge(bridgeHandler, this);
    }

    // 静态方法:关闭可关闭资源
    public static void close(Closeable closeable) {
        if (closeable!= null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 私有方法:启用 Zlzp 插件 JavaScript 桥接
    private void enableZlzpPluginJsBridge() {
        IManager pluginManager = ManagerPluginLoader.getInstance().getPluginManager();
        pluginJsBridge = new ZlzpPluginJsBridgeImpl(this, pluginManager);
        pluginJsBridge.enableJsBridge();
    }

    // 私有方法:获取 PC 端用户代理字符串
    private String getPCUa() {
        boolean isFollowSystemLanguage = LanguageHelper.isFollowSystemLanguage();
        if (!isFollowSystemLanguage) {
            String currentLanguageKey = LanguageHelper.getCurrentLanguageKey();
            if (currentLanguageKey!= null) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(" lang/").append(currentLanguageKey);
                return stringBuilder.toString();
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Mozilla/5.0 (Linux; x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Xwalk/53.0.2785.143 Chrome/53.0.2785.143 Safari/537.36 zlzp/%s");
        Object[] args = new Object[1];
        args[0] = AppVersion.getVersionName();
        return String.format(stringBuilder.toString(), args);
    }

    // 私有方法:初始化 XWalk
    private void initXWalk(Context context) {
        webViewId = Utils.randomId();
        XWalkPreferences.setValue("remote-debugging", true);
        XWalkPreferences.setValue("allow-universal-access-from-file", true);
        EvsXWalkResourceClient resourceClient = new EvsXWalkResourceClient(this, this);
        setResourceClient(resourceClient);
        EvsUiClient uiClient = new EvsUiClient(this, this);
        setUIClient(uiClient);
        setHorizontalFadingEdgeEnabled(false);
        setVerticalFadingEdgeEnabled(false);
        setFadingEdgeLength(0);
        setOverScrollMode(2);
        setKeepScreenOn(true);
        setZOrderOnTop(false);
        XWalkSettings settings = getSettings();
        settings.setLoadsImagesAutomatically(true);
        settings.setMediaPlaybackRequiresUserGesture(false);
        settings.setJavaScriptEnabled(true);
        settings.setAllowFileAccess(true);
        settings.setAllowUniversalAccessFromFileURLs(true);
        settings.setSupportZoom(false);
        settings.setBuiltInZoomControls(false);
        settings.setCacheMode(-1);
        settings.setDomStorageEnabled(true);
        settings.setDatabaseEnabled(true);
        settings.setInitialPageScale(100.0f);
        settings.setUseWideViewPort(false);
        String userAgent = getPCUa();
        settings.setUserAgentString(userAgent);
        XWalkCookieManager cookieManager = new XWalkCookieManager();
        this.cookieManager = cookieManager;
    }

    // 静态方法:将输入流转换为字符串
    public static String stream2String(InputStream inputStream) throws IOException {
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        StringBuilder stringBuilder = new StringBuilder();
        String line;
        while ((line = bufferedReader.readLine())!= null) {
            stringBuilder.append(line);
        }
        close(bufferedReader);
        close(inputStreamReader);
        close(inputStream);
        return stringBuilder.toString();
    }

    // 实现 IWebView 接口的方法:调用 JavaScript
    @Override
    public void callJs(String script, ValueCallback<String> callback) {
        Looper myLooper = Looper.myLooper();
        Looper mainLooper = Looper.getMainLooper();
        if (myLooper == mainLooper) {
            Object[] args = new Object[1];
            args[0] = script;
            String formattedScript = String.format("%s", args);
            evaluateJavascript(formattedScript, callback);
        } else {
            XWalkWebView$1 runnable = new XWalkWebView$1(this, script, callback);
            post(runnable);
        }
    }

    // 实现 IWebView 接口的方法:检查并返回上一页
    @Override
    public boolean checkAndGoBack() {
        XWalkNavigationHistory navigationHistory = getNavigationHistory();
        if (navigationHistory.canGoBack()) {
            navigationHistory.navigate(Direction.BACKWARD, 1);
            return true;
        } else {
            return false;
        }
    }

    // 实现 IWebView 接口的方法:获取布局参数
    @Override
    public LayoutParams getLayoutParams() {
        Rect positionInfo = this.positionInfo;
        if (positionInfo!= null) {
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(positionInfo.width(), positionInfo.height());
            layoutParams.leftMargin = positionInfo.left;
            layoutParams.topMargin = positionInfo.top;
            return layoutParams;
        } else {
            return super.getLayoutParams();
        }
    }

    // 实现 IWebView 接口的方法:获取父视图
    @Override
    public ViewParent getParentView() {
        return getParent();
    }

    // 实现 IWebView 接口的方法:获取 QsyBridge
    @Override
    public QsyBridge getQsyBridge() {
        return bridge;
    }

    // 实现 IWebView 接口的方法:获取网页视图
    @Override
    public View getWebView() {
        return this;
    }

    // 实现 IWebView 接口的方法:获取网页视图 ID
    @Override
    public String getWebViewId() {
        return webViewId;
    }

    // 实现 IWebView 接口的方法:加载数据
    @Override
    public void loadData(String data) {
        try {
            InputStream inputStream = getContext().getAssets().open(MANIFEST_ASSETS_PATH);
            String manifestString = stream2String(inputStream);
            JSONObject jsonObject = new JSONObject(manifestString);
            jsonObject.put("start_url", data);
            String updatedManifest = jsonObject.toString();
            loadAppFromManifest("", updatedManifest);
        } catch (IOException | JSONException e) {
            if (e instanceof JSONException) {
                e.printStackTrace();
            } else {
                XLog.e(TAG, "build xwalk config error!!!");
            }
        }
    }

    // 实现 IWebView 接口的方法:原生播放器支持
    @Override
    public boolean nativePlayer() {
        return true;
    }

    // 实现 IWebView 接口的方法:销毁
    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    // 实现 IWebView 接口的方法:处理新意图
    @Override
    public boolean onNewIntent(Intent intent) {
        return super.onNewIntent(intent);
    }

    // 实现 IWebView 接口的方法:暂停
    @Override
    public void onPause() {
        pauseTimers();
        onHide();
    }

    // 实现 IWebView 接口的方法:恢复
    @Override
    public void onResume() {
        resumeTimers();
        onShow();
    }

    // 实现 IWebView 接口的方法:重新加载
    @Override
    public void reload() {
        super.reload(1);
    }

    // 实现 IWebView 接口的方法:移除播放器视图
    @Override
    public void removePlayerView(IWebPlayer webPlayer) {
        WebViewClient webViewClient = this.webViewClient;
        if (webViewClient!= null) {
            webViewClient.removePlayerView(webPlayer);
        }
    }

    // 实现 IWebView 接口的方法:移除网页视图
    @Override
    public void removeWebView(IWebView webViewToRemove) {
        WebViewClient webViewClient = this.webViewClient;
        if (webViewClient!= null) {
            webViewClient.removeWebView(webViewToRemove);
        }
    }

    // 实现 IWebView 接口的方法:设置桥接处理器
    @Override
    public void setBridgeHandler(BridgeHandler bridgeHandler) {
        bridge = buildBridge(bridgeHandler);
        String bridgeName = bridge.getName();
        addJavascriptInterface(bridge, bridgeName);
    }

    // 实现 IWebView 接口的方法:设置 JavaScript 委托
    @Override
    public void setJsDelegate(JSDelegate jsDelegate) {
        this.jsDelegate = jsDelegate;
    }

    // 实现 IWebView 接口的方法:设置位置和大小
    @Override
    public void setPositionAndSize(int x, int y, int width, int height) {
        Rect positionInfo = this.positionInfo;
        if (positionInfo == null) {
            positionInfo = new Rect();
            this.positionInfo = positionInfo;
        }
        positionInfo.set(x, y, x + width, y + height);
    }

    // 实现 IWebView 接口的方法:设置网页视图客户端
    @Override
    public void setWebViewClient(WebViewClient webViewClient) {
        this.webViewClient = webViewClient;
    }

    // 实现 IWebView 接口的方法:显示播放器视图
    @Override
    public void showPlayerView(IWebPlayer webPlayer) {
        WebViewClient webViewClient = this.webViewClient;
        if (webViewClient!= null) {
            webViewClient.showPlayerView(webPlayer);
        }
    }

    // 实现 IWebView 接口的方法:显示网页视图
    @Override
    public void showWebView(IWebView webViewToShow) {
        WebViewClient webViewClient = this.webViewClient;
        if (webViewClient!= null) {
            webViewClient.showWebView(webViewToShow);
        }
    }
}

安卓WebPlayer工厂

java 复制代码
package com.qisyun.sunday.webview;

import android.content.Context;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class WebPlayerFactory {
    // 静态字段
    private static final Map<String, IWebPlayer> repos;

    // 静态初始化块
    static {
        repos = new HashMap<>();
    }

    // 私有构造方法
    private WebPlayerFactory() {
        super();
    }

    // 创建 Web 播放器实例并将其存储在映射中
    public static IWebPlayer create(Context context, WebPlayerFactory.Creator creator) {
        IWebPlayer webPlayer = creator.create(context);
        repos.put(webPlayer.getPlayerId(), webPlayer);
        return webPlayer;
    }

    // 释放所有播放器
    public static void disposeAllPlayer() {
        Set<Map.Entry<String, IWebPlayer>> entrySet = repos.entrySet();
        Iterator<Map.Entry<String, IWebPlayer>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, IWebPlayer> entry = iterator.next();
            IWebPlayer webPlayer = entry.getValue();
            if (webPlayer!= null) {
                webPlayer.stop();
            }
        }
        repos.clear();
    }

    // 根据播放器 ID 释放特定播放器
    public static void disposePlayer(String playerId) {
        repos.remove(playerId);
    }

    // 根据播放器 ID 获取播放器实例
    public static IWebPlayer getPlayer(String playerId) {
        return repos.get(playerId);
    }

    // 内部接口用于创建 Web 播放器
    public interface Creator {
        IWebPlayer create(Context context);
    }
}

安卓原生播放器

java 复制代码
package com.qisyun.sunday.activities.component.welcome;

import android.content.Context;
import android.graphics.Point;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.View.MeasureSpec;

import java.util.Map;

public class VideoView extends TextureView {
    // 静态字段
    private static final int STATE_ERROR = -1;
    private static final int STATE_IDLE = 0;
    private static final int STATE_PAUSED = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;
    private static final int STATE_PLAYING = 3;
    private static final int STATE_PREPARED = 2;
    private static final int STATE_PREPARING = 1;
    private static final String TAG = "VideoView";

    // 实例字段
    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener;
    private MediaPlayer.OnCompletionListener mCompletionListener;
    private int mCurrentBufferPercentage;
    private int mCurrentState;
    private MediaPlayer.OnErrorListener mErrorListener;
    private Map<String, String> mHeaders;
    private MediaPlayer.OnInfoListener mInfoListener;
    private MediaPlayer mMediaPlayer;
    private MediaPlayer.OnCompletionListener mOnCompletionListener;
    private MediaPlayer.OnErrorListener mOnErrorListener;
    private MediaPlayer.OnInfoListener mOnInfoListener;
    private MediaPlayer.OnPreparedListener mOnPreparedListener;
    private MediaPlayer.OnPreparedListener mPreparedListener;
    private int mSeekWhenPrepared;
    private MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener;
    private Surface mSurface;
    private int mSurfaceHeight;
    private int mSurfaceWidth;
    private int mTargetState;
    private Uri mUri;
    private int mVideoHeight;
    private int mVideoWidth;
    private TextureView.SurfaceTextureListener textureListener;

    // 构造方法
    public VideoView(Context context) {
        this(context, null);
    }

    public VideoView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 设置视频大小变化监听器
        mSizeChangedListener = new VideoView$1(this);
        setOnVideoSizeChangedListener(mSizeChangedListener);
        // 设置视频准备好监听器
        mPreparedListener = new VideoView$2(this);
        setOnPreparedListener(mPreparedListener);
        // 设置视频播放完成监听器
        mCompletionListener = new VideoView$3(this);
        setOnCompletionListener(mCompletionListener);
        // 设置视频信息监听器
        mInfoListener = new VideoView$4(this);
        setOnInfoListener(mInfoListener);
        // 设置视频错误监听器
        mErrorListener = new VideoView$5(this);
        setOnErrorListener(mErrorListener);
        // 设置视频缓冲更新监听器
        mBufferingUpdateListener = new VideoView$6(this);
        setOnBufferingUpdateListener(mBufferingUpdateListener);
        // 设置纹理监听器
        textureListener = new VideoView$7(this);
        setSurfaceTextureListener(textureListener);
        mVideoWidth = 0;
        mVideoHeight = 0;
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        mCurrentState = STATE_IDLE;
        mTargetState = STATE_IDLE;
    }

    // 静态方法访问器
    static int access$000(VideoView videoView) {
        return videoView.mVideoWidth;
    }

    static int access$002(VideoView videoView, int value) {
        return videoView.mVideoWidth = value;
    }

    static int access$100(VideoView videoView) {
        return videoView.mVideoHeight;
    }

    static int access$1002(VideoView videoView, int value) {
        return videoView.mCurrentBufferPercentage = value;
    }

    static int access$102(VideoView videoView, int value) {
        return videoView.mVideoHeight = value;
    }

    static Surface access$1102(VideoView videoView, Surface surface) {
        return videoView.mSurface = surface;
    }

    static int access$1202(VideoView videoView, int value) {
        return videoView.mSurfaceWidth = value;
    }

    static int access$1302(VideoView videoView, int value) {
        return videoView.mSurfaceHeight = value;
    }

    static void access$1400(VideoView videoView) {
        videoView.openVideo();
    }

    static void access$1500(VideoView videoView, boolean releaseImmediately) {
        videoView.release(releaseImmediately);
    }

    static int access$202(VideoView videoView, int value) {
        return videoView.mCurrentState = value;
    }

    static MediaPlayer.OnPreparedListener access$300(VideoView videoView) {
        return videoView.mOnPreparedListener;
    }

    static MediaPlayer access$400(VideoView videoView) {
        return videoView.mMediaPlayer;
    }

    static int access$500(VideoView videoView) {
        return videoView.mSeekWhenPrepared;
    }

    static int access$600(VideoView videoView) {
        return videoView.mTargetState;
    }

    static int access$602(VideoView videoView, int value) {
        return videoView.mTargetState = value;
    }

    static MediaPlayer.OnCompletionListener access$700(VideoView videoView) {
        return videoView.mOnCompletionListener;
    }

    static MediaPlayer.OnInfoListener access$800(VideoView videoView) {
        return videoView.mOnInfoListener;
    }

    static MediaPlayer.OnErrorListener access$900(VideoView videoView) {
        return videoView.mOnErrorListener;
    }

    // 判断是否处于播放状态
    private boolean isInPlaybackState() {
        MediaPlayer mediaPlayer = mMediaPlayer;
        if (mediaPlayer == null) {
            return false;
        }
        int currentState = mCurrentState;
        return currentState!= STATE_ERROR && currentState!= STATE_IDLE && currentState!= 1;
    }

    // 打开视频
    private void openVideo() {
        Uri uri = mUri;
        if (uri!= null && mSurface!= null) {
            release(false);
            MediaPlayer mediaPlayer = new MediaPlayer();
            setMediaPlayerListeners(mediaPlayer);
            try {
                mediaPlayer.setDataSource(getContext(), uri, mHeaders);
                mediaPlayer.setSurface(mSurface);
                mediaPlayer.setScreenOnWhilePlaying(true);
                mediaPlayer.prepareAsync();
                mCurrentState = STATE_PREPARING;
            } catch (IOException | IllegalArgumentException e) {
                Log.w(TAG, "Unable to open content: " + uri, e);
                mCurrentState = STATE_ERROR;
                mTargetState = STATE_ERROR;
                if (mErrorListener!= null && mediaPlayer!= null) {
                    mErrorListener.onError(mediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
                }
            }
        }
    }

    // 设置媒体播放器监听器
    private void setMediaPlayerListeners(MediaPlayer mediaPlayer) {
        mediaPlayer.setOnPreparedListener(mPreparedListener);
        mediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
        mediaPlayer.setOnCompletionListener(mCompletionListener);
        mediaPlayer.setOnErrorListener(mErrorListener);
        mediaPlayer.setOnInfoListener(mInfoListener);
        mediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
    }

    // 释放视频资源
    private void release(boolean releaseImmediately) {
        MediaPlayer mediaPlayer = mMediaPlayer;
        if (mediaPlayer!= null) {
            mediaPlayer.reset();
            mediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            if (releaseImmediately) {
                mTargetState = STATE_IDLE;
            }
        }
    }

    // 获取缓冲百分比
    public int getBufferPercentage() {
        MediaPlayer mediaPlayer = mMediaPlayer;
        if (mediaPlayer!= null) {
            return mCurrentBufferPercentage;
        } else {
            return 0;
        }
    }

    // 获取当前播放位置
    public int getCurrentPosition() {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null) {
                return mediaPlayer.getCurrentPosition();
            }
        }
        return 0;
    }

    // 获取视频总时长
    public int getDuration() {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null) {
                return mediaPlayer.getDuration();
            }
        }
        return -1;
    }

    // 判断视频是否正在播放
    public boolean isPlaying() {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null && mediaPlayer.isPlaying()) {
                return true;
            }
        }
        return false;
    }

    // 测量视图大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int videoWidth = mVideoWidth;
        int videoHeight = mVideoHeight;
        if (videoWidth > 0 && videoHeight > 0) {
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
                // 特殊处理
                //...
            } else {
                // 不同情况下的处理
                //...
            }
            setMeasuredDimension(widthSize, heightSize);
        }
    }

    // 暂停播放
    public void pause() {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null && mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
                mCurrentState = STATE_PAUSED;
                mTargetState = STATE_PAUSED;
            }
        } else {
            mTargetState = STATE_PAUSED;
        }
    }

    // 恢复播放
    public void resume() {
        openVideo();
    }

    // 跳转到指定位置
    public void seekTo(int position) {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null) {
                mediaPlayer.seekTo(position);
                mSeekWhenPrepared = 0;
            }
        } else {
            mSeekWhenPrepared = position;
        }
    }

    // 设置播放完成监听器
    public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
        mOnCompletionListener = listener;
    }

    // 设置错误监听器
    public void setOnErrorListener(MediaPlayer.OnErrorListener listener) {
        mOnErrorListener = listener;
    }

    // 设置信息监听器
    public void setOnInfoListener(MediaPlayer.OnInfoListener listener) {
        mOnInfoListener = listener;
    }

    // 设置准备好监听器
    public void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) {
        mOnPreparedListener = listener;
    }

    // 设置视频路径
    public void setVideoPath(String path) {
        setVideoURI(Uri.parse(path));
    }

    // 设置视频 URI
    public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }

    // 设置视频 URI 和头部信息
    public void setVideoURI(Uri uri, Map<String, String> headers) {
        mUri = uri;
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        openVideo();
        requestLayout();
        invalidate();
    }

    // 开始播放
    public void start() {
        if (isInPlaybackState()) {
            MediaPlayer mediaPlayer = mMediaPlayer;
            if (mediaPlayer!= null) {
                mediaPlayer.start();
                mCurrentState = STATE_PLAYING;
                mTargetState = STATE_PLAYING;
            }
        } else {
            mTargetState = STATE_PLAYING;
        }
    }

    // 停止播放
    public void stopPlayback() {
        MediaPlayer mediaPlayer = mMediaPlayer;
        if (mediaPlayer!= null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
        }
    }

    // 暂停播放并释放资源
    public void suspend() {
        release(false);
    }
}
相关推荐
小冷爱学习!10 小时前
华为动态路由-OSPF-完全末梢区域
服务器·网络·华为
2501_9044477410 小时前
华为发力中端,上半年nova14下半年nova15,大力普及原生鸿蒙
华为·智能手机·django·scikit-learn·pygame
MarkHD11 小时前
第十八天 WebView深度优化指南
华为·harmonyos
塞尔维亚大汉12 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI CSI】
harmonyos·领域驱动设计
别说我什么都不会12 小时前
鸿蒙轻内核M核源码分析系列十五 CPU使用率CPUP
操作系统·harmonyos
feiniao865113 小时前
2025年华为手机解锁BL的方法
华为·智能手机
塞尔维亚大汉14 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【I3C】
harmonyos·领域驱动设计
VVVVWeiYee14 小时前
BGP配置华为——路径优选验证
运维·网络·华为·信息与通信
今阳16 小时前
鸿蒙开发笔记-6-装饰器之@Require装饰器,@Reusable装饰器
android·app·harmonyos
余多多_zZ16 小时前
鸿蒙初学者学习手册(HarmonyOSNext_API14)_组件截图(@ohos.arkui.componentSnapshot (组件截图) )
学习·华为·harmonyos·鸿蒙·鸿蒙系统