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);
    }
}
相关推荐
Bert.King16 分钟前
<HarmonyOS第一课>给应用添加通知和提醒的习题
华为·harmonyos
法迪11 小时前
华为手机系统应用瘦身
华为·智能手机·功耗
觉醒法师13 小时前
HarmonyOS开发 - 本地持久化之实现LocalStorage支持多实例
前端·javascript·华为·typescript·harmonyos
东林知识库16 小时前
2024年10月HarmonyOS应用开发者基础认证全新题库
学习·华为·harmonyos
ChinaDragonDreamer16 小时前
HarmonyOS:@Watch装饰器:状态变量更改通知
开发语言·harmonyos·鸿蒙
Lei活在当下21 小时前
【初探鸿蒙01】鸿蒙生态用开发白皮书V3.0解读
harmonyos
法迪1 天前
华为手机卸载系统应用的方法
华为·智能手机
Xzzzz9111 天前
华为配置 之 STP
服务器·网络·计算机网络·华为
SameX1 天前
实现多子类型输入法:如何在 HarmonyOS中加载不同的输入模式
harmonyos