当前位置:   article > 正文

腾讯x5内核(TBS)集成使用详解(webView视频播放)_集成tbs后打开视频卡

集成tbs后打开视频卡

腾讯x5内核(TBS)集成使用详解(webView视频播放)
腾讯x5内核(TBS)集成简单,目前在腾讯的QQ和微信中均有使用。
相对于android的系统内核来说,TBS简直太完美了
TBS(腾讯浏览服务)的优势

  1. 速度快:相比系统webview的网页打开速度有30+%的提升;
  2. 省流量:使用云端优化技术使流量节省20+%;
  3. 更安全:安全问题可以在24小时内修复;
  4. 更稳定:经过亿级用户的使用考验,CRASH率低于0.15%;
  5. 兼容好:无系统内核的碎片化问题,更少的兼容性问题;
  6. 体验优:支持夜间模式、适屏排版、字体设置等浏览增强功能;
  7. 功能全:在Html5、ES6上有更完整支持;
  8. 更强大:集成强大的视频播放器,支持视频格式远多于系统webview;
  9. 视频和文件格式的支持x5内核多于系统内核
  10. 防劫持是x5内核的一大亮点

如果是在项目中使用过android的webview之后,就能明白系统自带的各种坑。当初功能上线之后。遇到以下问题

  1. 魅族手机上部分页面加载不出来
  2. android低版本上部分js语法根本无法使用。
  3. 华为手机部分机型加载页面超级慢
  4. 复杂页面卡顿感十分明显
  5. 视频播放服务实现困难,都是原生自己实现。当触发全屏等操作的时候,效果很不好。
  6. 安全扫描的时候直接就能扫描出安全漏洞。webView注入漏洞 android 4.2以下

后来更换了腾讯x5内核(TBS),实现的效果远好于预期。

腾讯TBS官网 下载android的SDK后。解压,找到需要的jar包。
放入so文件和jar包文件分别放到src->jniLibs->armeabi和libs目录下,项目中添加这两项的依赖。

在application中添加sdk初始化的代码。

 QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
            @Override
            public void onViewInitFinished(boolean arg0) {
                //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
                Log.d("app", "腾讯X5内核初始化回调 onViewInitFinished is " + arg0);
            }
            @Override
            public void onCoreInitFinished() {
                Log.d("app", "腾讯X5内核初始化回调 onCoreInitFinished");
            }
        };
        //x5内核初始化接口
        QbSdk.initX5Environment(getApplicationContext(), cb);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

sdk初始化之后,构建一个BaseTencentWebActivity
界面配置文件为:

 <RelativeLayout
        android:id="@+id/rl_toolbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/titleheight"
        android:background="@drawable/mt_bg_title">

        <ImageButton
            android:id="@+id/ibLeft"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:background="@drawable/mt_bg_imagebutton"
            android:contentDescription="@string/app_name"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:src="@drawable/mt_ic_left" />

        <TextView
            android:id="@+id/tvTitle"
            style="@style/titletext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="40dp"
            android:layout_marginRight="40dp"
            android:ellipsize="end" />
        <ImageButton
            android:id="@+id/ibRight"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_toLeftOf="@id/ibRight1"
            android:background="@drawable/mt_bg_imagebutton"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:visibility="gone" />
    </RelativeLayout>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="3dip"
        android:max="100"
        android:progressDrawable="@drawable/mt_progress_horizontal" />

    <com.tencent.smtt.sdk.WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
public abstract class BaseTencenWebactivity extends BaseActivity {
    protected RelativeLayout rlToolbar;
    protected ImageButton ibLeft1;
    protected ImageButton ibRight2;
    protected WebView webView;
    protected TextView tvTitle;
    protected ProgressBar progressBar;

    protected static final String HYBRID = "HYBRID";    //js调用android时候,android注入的对象名称

    public static final String FROM_WHERE = "H5";   //跳转来源H5;

    @Override
    public void setContentView() {
        setContentView(R.layout.activity_base_tencen_web);
    }

    @Override
    public void init() {
        rlToolbar = (RelativeLayout) findViewById(R.id.rl_toolbar);
        ibLeft1 = (ImageButton) findViewById(R.id.ibLeft1);
        ibRight2 = (ImageButton) findViewById(R.id.ibRight2);
        tvTitle = (TextView) findViewById(R.id.tvTitle);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        progressBar.setVisibility(View.VISIBLE);
        progressBar.setProgress(0);

        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setUseWideViewPort(true);
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.getSettings().setBlockNetworkImage(false);
        webView.getSettings().setBlockNetworkLoads(false);
        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setBuiltInZoomControls(true);
        webView.getSettings().setDisplayZoomControls(false);
        webView.getSettings().setGeolocationEnabled(true);
        webView.getSettings().setSupportZoom(true);
        webView.getSettings().setUserAgentString("Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn;) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/37.0.0.0 MQQBrowser/6.3 Mobile Safari/537.36");
        onWebViewSettingBuild();
        configPlaySetting();
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
            injectJavaScript();
        }
        if (isNoWebCache()) {
            webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        }
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.startsWith("https") || url.startsWith("http") ) {
                    view.loadUrl(url);
                    progressBar.setVisibility(View.VISIBLE);
                    progressBar.setProgress(0);
                    BaseTencenWebactivity.this.shouldOverrideUrlLoading(view, url);
                }
                return false;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                progressBar.setVisibility(View.GONE);
                super.onPageFinished(view, url);
                BaseTencenWebactivity.this.onPageFinished(view, url);
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                BaseTencenWebactivity.this.onPageStarted(view, url, favicon);
            }

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                if (enabledHTTPS()) {
                    //当启用https,遇到证书错误的时候,直接调用handler.proceed实际上是存在安全因素的。
                    //实际上可以根据不同的错误类型,来做调整。比如遇到一个不可信的证书。 SslError.SSL_UNTRUSTED
                    //可以像其他浏览器那样,弹出对话框提示,提示用户证书不可信等。
                    handler.proceed();
                } else {
                    super.onReceivedSslError(view, handler, error);
                }

            }
        });
        webView.setWebChromeClient(new WebChromeClient() {

            private View myView;
            @Override
            public void onProgressChanged(WebView view, int progress) {
                progressBar.setProgress(progress);
                BaseTencenWebactivity.this.onProgressChanged(view, progress);
            }

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                return handleJsPrompt(view, url, message, defaultValue, result);
            }

            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                return handleJsAlert(view, url, message, result);
            }

            @Override
            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
                return handleJsConfirm(view, url, message, result);
            }

            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                MyLog.i(getClass().getName(), String.format("[%s] sourceID: %s lineNumber: %s message: %s",
                        consoleMessage.messageLevel(), consoleMessage.sourceId(), consoleMessage.lineNumber(), consoleMessage.message()));
                return super.onConsoleMessage(consoleMessage);
            }

            @Override
            public void onReceivedTitle(WebView webView, String s) {
                tvTitle.setText(s);
            }

            //自定义视频播放  如果需要启用这个,需要设置x5,自己实现全屏播放。目前的使用的x5的视频播放
            //如果是点击h5 vedio标签的播放,需要自己实现全屏播放
            @Override
            public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
                super.onShowCustomView(view, customViewCallback);
                ViewGroup parent = (ViewGroup) webView.getParent();
                parent.removeView(webView);

                // 设置背景色为黑色
                view.setBackgroundColor(BaseTencenWebactivity.this.getResources().getColor(R.color.black));
                parent.addView(view);
                myView = view;
                rlToolbar.setVisibility(View.GONE);
                setFullScreen();
            }

            @Override
            public void onHideCustomView() {
                super.onHideCustomView();
                if (myView != null) {
                    ViewGroup parent = (ViewGroup) myView.getParent();
                    parent.removeView(myView);
                    parent.addView(webView);
                    myView = null;
                    rlToolbar.setVisibility(View.VISIBLE);
                    quitFullScreen();
                }
            }

        });
        tvTitle.setText(getWebViewTitle());
        String url = getUrl();
        if (!TextUtils.isEmpty(url)) {
            loadUrl(url);
        }

    }

    /**
     * 播放设置    已经开启x5全屏  小窗播放  页内播放等。
     */
    protected void configPlaySetting(){
        Bundle data = new Bundle();
//true表示标准全屏,false表示X5全屏;不设置默认false,
        data.putBoolean("standardFullScreen", false);
//false:关闭小窗;true:开启小窗;不设置默认true,
        data.putBoolean("supportLiteWnd", true);
//1:以页面内开始播放,2:以全屏开始播放;不设置默认:1
        data.putInt("DefaultVideoScreen", 1);
        webView.getX5WebViewExtension().invokeMiscMethod("setVideoParams", data);
//        standardFullScreen 全屏设置
//
//        设置为true时,我们会回调WebChromeClient的onShowCustomView方法,由开发者自己实现全屏展示;
//
//        设置为false时,由我们实现全屏展示,我们实现全屏展示需要满足下面两个条件:
//
//        a. 我们 Webview初始化的Context必须是Activity类型的Context
//
//        b. 我们 Webview 所在的Activity要声明这个属性
//
//        android:configChanges="orientation|screenSize|keyboardHidden"
//        如果不满足这两个条件,standardFullScreen 自动置为 true
//        supportLiteWnd 小窗播放设置
//
//        前提standardFullScreen=false,这个条件才生效
//
//        设置为 true, 开启小窗功能
//
//        设置为 false,不使用小窗功能
//
//        DefaultVideoScreen 初始播放形态设置
//
//        a、以页面内形态开始播放
//
//        b、以全屏形态开始播放

    }


    /**
     *设置全屏
     */
    private void setFullScreen(){
        BaseTencenWebactivity.this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }


    /**
     * 退出全屏
     */
    private void quitFullScreen() {
        // 声明当前屏幕状态的参数并获取
        final WindowManager.LayoutParams attrs = BaseTencenWebactivity.this.getWindow().getAttributes();
        attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
        BaseTencenWebactivity.this.getWindow().setAttributes(attrs);
        BaseTencenWebactivity.this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    }

    /**
     * 播放视频  传入视频的url地址
     * @return
     */
    protected boolean playVideoByTbs(String videoUrl){
        if(TbsVideo.canUseTbsPlayer(BaseTencenWebactivity.this)){
            //播放器是否可以使用
            Bundle xtraData = new Bundle();
            xtraData.putInt("screenMode", 102);//全屏设置 和控制栏设置
            TbsVideo.openVideo(BaseTencenWebactivity.this,videoUrl, xtraData);
            return true;
        }else{
            return false;
        }
    }

    /**
     * 是否在android中处理Js的Prompt弹出框
     * false不处理,true可拦截处理
     */
    protected boolean handleJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        return false;
    }

    /**
     * 是否在android中处理Js的Alert弹出框
     * false不处理,true可拦截处理
     */
    protected boolean handleJsAlert(WebView view, String url, String message, JsResult result) {
        return false;
    }

    /**
     * 是否在android中处理Js的Confirm弹出框
     * false不处理,true可拦截处理
     */
    protected boolean handleJsConfirm(WebView view, String url, String message, JsResult result) {
        return false;
    }

    /**
     * 注入javaScript对象
     */
    @SuppressLint("AddJavascriptInterface")
    private void injectJavaScript() {
        webView.addJavascriptInterface(getJavascriptInterface(), HYBRID);
    }

    /**
     * 返回 注入javaScript对象,必须继承 {@link BaseHYBRID}
     *
     * @return T extend BaseHYBRID
     */
    protected BaseHYBRID getJavascriptInterface() {
        return new BaseHYBRID();
    }

    protected boolean enabledHTTPS() {
        return Tools.getBooleanExtra(getIntent(), "enabledHTTPS", false);
    }
    
    

    /**
     * 调用javascript方法
     *
     * @param js
     */
    protected void loadJavaScript(String js) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //sdk>19才有
            webView.evaluateJavascript(js, new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String responseJson) {
                    //这里获取的参数就是JS函数的返回值
                }
            });
        } else {
            //SDK <= 19
            webView.loadUrl(js);
        }
    }

    protected void onWebViewSettingBuild() {

    }

    protected void loadUrl(String url) {
        webView.loadUrl(url);
    }

    /**
     * 不用缓存,true:无缓存,false:默认
     *
     * @return
     */
    protected boolean isNoWebCache() {
        return false;
    }

    protected String getWebViewTitle() {
        return getIntent().getStringExtra("title");
    }

    public String getUrl() {
        return getIntent().getStringExtra("url");
    }
    

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (webView.canGoBack()) {
                webView.goBack();
            } else {
                back();
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    protected void shouldOverrideUrlLoading(WebView view, String url) {
    }

    protected void onPageFinished(WebView view, String url) {
    }

    protected void onPageStarted(WebView view, String url, Bitmap favicon) {
    }

    protected void onProgressChanged(WebView view, int progress) {
    }

    /**
     * 公共的JS行为基类,封装通用的操作给第三方
     */
    public class BaseHYBRID {

        /**
         * 退出当前页面
         */
        @JavascriptInterface
        public void exitPage() {
            back();
        }

        /**
         * 设置页面标题
         *
         * @param title
         */
        @JavascriptInterface
        public void setTitle(String title) {
            setTitleOnUiThread(title);
        }

        public void setTitleOnUiThread(final String title) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    tvTitle.setText(title);
                }
            });
        }
    }

    @Override
    protected void onDestroy() {
        webView.stopLoading();
        webView.removeAllViews();
        webView.destroy();
        webView = null;
        super.onDestroy();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398

以上就封装了一个能够正常播放视频,能够小窗播放,h5传入视频地址就能正常播放的浏览器。其中tbsVedio是内置的一个播放方法,传入url地址就行了,如果需要播放网页中嵌入的视频,在全屏和非全屏之间的切换时,需要实现onShowCustomView和onHideCustomView两个方法。

到这里腾讯x5内核(TBS)就集成完毕了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/864193
推荐阅读
  

闽ICP备14008679号