ionic3使用X5内核预览常用文件

x5内核运行顺序,结合logcat日志的理解:
1、初始化开始;QbSdk.initX5Environment
2、初始化成功;(QbSdk.isTbsCoreInited()返回true)
3、下载x5内核(不断打印下载百分比);onDownloadProgress
4、x5下载完成;onDownloadFinish
5、x5安装完成;onInstallFinish

下载Android SDK(完整版)
引入tbs Android SDK文件

  • 把*.jar文件复制到app/libs/目录下
  • 加入到库,引入成功后,会自动在build.gradle中加入implementation files('libs/tbs_sdk_thirdapp_v4.3.0.3_43903_sharewithdownloadwithfile_withoutGame_obfs_20200402_121309.jar')代码;
    image.png

1、X5FileOpen.java

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\java\com\wanm\exxteacher\X5FileOpen.java

package com.wanm.exxteacher;

import android.content.Context;
import android.util.Log;

import com.tencent.smtt.sdk.QbSdk;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;

public class X5FileOpen extends CordovaPlugin {

  public void openFile(String filepath, String filename, CallbackContext callbackContext) {
    Context context = this.cordova.getActivity();
    String filePath = filepath.substring(7);
    String fileName = filename;
//    Log.d("wjb-open", "路径:" + filePath+","+QbSdk.isTbsCoreInited()+","+MainActivity.isX5Loaded);
    if (!QbSdk.isTbsCoreInited()) {
      callbackContext.error("插件正在初始化,请等待...");
      return;
    }
    if (!MainActivity.isX5Loaded) {
      callbackContext.error("插件正在初始化,请等待...");
      return;
    }
    DisplayFileActivity.openDispalyFileActivity(context, filePath, fileName);
  }

  @Override
  public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    if ("openFile".equals(action)) {
      String filepath = args.getString(0);
      String filename = args.getString(1);
      openFile(filepath, filename, callbackContext);
      return true;
    }
    return false;
  }
}

2、MainActivity.java

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\java\com\wanm\exxteacher\MainActivity.java

package com.wanm.exxteacher;

import android.content.SharedPreferences;
import android.os.Bundle;

import org.apache.cordova.*;

import com.tencent.smtt.sdk.QbSdk;
import com.tencent.smtt.sdk.TbsListener;

import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;
//import java.util.Timer;
//import java.util.TimerTask;

public class MainActivity extends CordovaActivity {
  static boolean isX5Loaded = true;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // enable Cordova apps to be started in the background
    Bundle extras = getIntent().getExtras();
    if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
      moveTaskToBack(true);
    }

    // Set by <content src="index.html" /> in config.xml
    loadUrl(launchUrl);

    // 覆盖安装后首次打开,重置x5内核
    SharedPreferences preferences = getSharedPreferences("first_open", MODE_PRIVATE);
    boolean isFirstIn = preferences.getBoolean("is_first_open", true);
    if (isFirstIn) {
      //第一次进入时先把first_open置为false以便后来进入时进行判断,除此之外,还可以写入第一次进入时苏要执行的动作
      preferences = getSharedPreferences("first_open", MODE_PRIVATE);
      SharedPreferences.Editor editor = preferences.edit();
      editor.putBoolean("is_first_open", false);
      editor.commit();
//      Log.d("wjb", "第一次进入,reset重置完成");
      QbSdk.reset(this);
    } else {
      //不是第一次进入时所要做的动作
//      Log.d("wjb", "不是第一次进入");
    }

    //X5内核初始化,延时10秒,防止和热更新冲突
    Timer t = new Timer();
    t.schedule(new TimerTask() {
      public void run() {
        initX5();
        preinitX5WebCore();
        this.cancel();
      }
    }, 10000);

//    initX5Timer();//检测是否初始化完成

    QbSdk.setTbsListener(new TbsListener() {
      @Override
      public void onDownloadFinish(int i) {
//        Log.d("wjb-listen", "onDownloadFinish");
        isX5Loaded = false;
      }

      @Override
      public void onInstallFinish(int i) {
//        Log.d("wjb-listen", "onInstallFinish");
        isX5Loaded = true;
      }

      @Override
      public void onDownloadProgress(int i) {
//        Log.d("wjb-listen", "onDownloadProgress:" + i);
        isX5Loaded = false;
      }
    });
  }

  //  private void initX5Timer() {
//    //创建定时器对象
//    Timer t = new Timer();
//    if (!QbSdk.isTbsCoreInited()) {
//      Log.d("wjb-timer", "失败:" + num);
//      //在3秒后执行MyTask类中的run方法
//      t.schedule(new TimerTask() {
//        public void run() {
////          initX5();
//          initX5Timer();
//          this.cancel();
//        }
//      }, 2000);
//    } else {
//      Log.d("wjb-timer", "成功:" + num);
//    }
//  }
  private void preinitX5WebCore() {
    if (!QbSdk.isTbsCoreInited()) {
//      Log.d("wjb", "x5内核初始化失败");
      // preinit只需要调用一次,如果已经完成了初始化,那么就直接构造view
      QbSdk.preInit(MainActivity.this, null);// 设置X5初始化完成的回调接口
    }
  }

//  private Integer num = 1;

  /**
   * 初始化x5内核并加载
   */
  private void initX5() {
//    Log.d("wjb", "x5内核进入初始化程序" + num);
    //QbSdk.isTbsCoreInited()用来判断x5内核是否已经加载了
    if (QbSdk.isTbsCoreInited()) {
      //如果已经加载
//      Log.d("wjb", "QbSdk.isTbsCoreInited: true 已经加载x5内核");
    } else {
      //还没加载,就要初始化内核并加载
//      Log.d("wjb", "QbSdk.isTbsCoreInited: false 还没加载x5内核");
      QbSdk.setDownloadWithoutWifi(true);//非wifi条件下允许下载X5内核

      //初始化x5内核
      QbSdk.initX5Environment(this, new QbSdk.PreInitCallback() {
        @Override
        public void onCoreInitFinished() {
        }

        @Override
        public void onViewInitFinished(boolean b) {
          if (b == true) {
//            Log.d("wjb", "x5内核初始化成功");
          } else {
//            Log.d("wjb", "x5内核初始化失败");
//            num++;
            initX5();
          }
        }
      });
    }
  }
}

3、build.gradle

D:\Apps\ESchoolApp_Debug\platforms\android\app\build.gradle

android {

    defaultConfig {
        ...
        //引用tbsplus
        ndk {
          //选择要添加的对应cpu类型的.so库 不能添加arm64-v8a 不然x5内核加载不上去
          abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
        }
    }
}
dependencies {
  implementation fileTree(include: '*.jar', dir: 'libs')
  // SUB-PROJECT DEPENDENCIES START
  implementation project(path: ':CordovaLib')
  compile 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0'
  compile 'com.android.support:support-v4:24.1.1+'
  compile 'com.soundcloud.android:android-crop:1.0.0@aar'
  compile 'com.android.support:support-v4:27.+'
  compile 'com.android.support:appcompat-v7:27+'     //-------------这个版本必须对

  //运行时权限
  compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar'
  compile 'io.reactivex.rxjava2:rxjava:2.0.2'
  compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
  implementation files('libs/tbs_sdk_thirdapp_v4.3.0.1020_43633_sharewithdownload_withoutGame_obfs_20190111_105200.jar')
}

4、config.xml

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\res\xml\config.xml

    <feature name="X5FileOpen">
      <param name="android-package" value="com.wanm.exxteacher.X5FileOpen" />
    </feature>

5、AndroidManifest.xml

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\AndroidManifest.xml

<!-- TBS预览文件界面 -->
<activity android:name=".DisplayFileActivity" android:theme="@style/Theme.AppCompat"></activity>

6、DisplayFileActivity.java

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\java\com\wanm\exxteacher\DisplayFileActivity.java

package com.wanm.exxteacher;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.tbruyelle.rxpermissions2.RxPermissions;
import com.tencent.smtt.sdk.TbsReaderView;

import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;

/**
 * Created by HaiyuKing
 * Used 调用腾讯浏览服务预览文件
 */

public class DisplayFileActivity extends AppCompatActivity{

  private static final String TAG = DisplayFileActivity.class.getSimpleName();

  private TbsReaderView mTbsReaderView;//用于预览文件5-1

  private String filePath = "";
  private String fileName = "";

  public static void openDispalyFileActivity(Context context,String filePath,String fileName){
    Intent intent = new Intent(context,DisplayFileActivity.class);
    intent.putExtra("filepath",filePath);
    intent.putExtra("filename",fileName);
    context.startActivity(intent);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_displayfile);

    initTbsReaderView();//用于预览文件5-2

    Intent intent = getIntent();
    filePath = intent.getStringExtra("filepath");
    fileName = intent.getStringExtra("filename");

    onePermission();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mTbsReaderView.onStop();//用于预览文件5-5
  }

  //初始化TbsReaderView 5-3
  private void initTbsReaderView(){
    mTbsReaderView = new TbsReaderView(DisplayFileActivity.this, new TbsReaderView.ReaderCallback(){
      @Override
      public void onCallBackAction(Integer integer, Object o, Object o1) {
        //ReaderCallback 接口提供的方法可以不予处理(目前不知道有什么用途,但是一定要实现这个接口类)
      }
    });
    RelativeLayout rootRl = (RelativeLayout) findViewById(R.id.root_layout);
    rootRl.addView(mTbsReaderView, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  }
  //预览文件5-4
  /**
   * filePath :文件路径。格式为 android 本地存储路径格式,例如:/sdcard/Download/xxx.doc. 不支持 file:///格式。暂不支持在线文件。
   * fileName : 文件的文件名(含后缀)*/
  private void displayFile(String filePath,String fileName) {
    Bundle bundle = new Bundle();
    bundle.putString("filePath", filePath);
    bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath());
    boolean result = mTbsReaderView.preOpen(parseFormat(fileName), false);
    if (result) {
      mTbsReaderView.openFile(bundle);
    }
  }

  private String parseFormat(String fileName) {
    return fileName.substring(fileName.lastIndexOf(".") + 1);
  }

  /**只有一个运行时权限申请的情况*/
  private void onePermission(){
    RxPermissions rxPermissions = new RxPermissions(DisplayFileActivity.this); // where this is an Activity instance
    rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开
      .subscribe(new Consumer<Boolean>() {
        @Override
        public void accept(Boolean granted) throws Exception {
          Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
          if (granted) { // 在android 6.0之前会默认返回true
            // 已经获取权限
            //Toast.makeText(DisplayFileActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
          } else {
            // 未获取权限
            Toast.makeText(DisplayFileActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
          }
        }
      }, new Consumer<Throwable>() {
        @Override
        public void accept(Throwable throwable) throws Exception {
          Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
        }
      }, new Action() {
        @Override
        public void run() throws Exception {
          Log.e(TAG,"{run}");//执行顺序——2
          displayFile(filePath,fileName);
        }
      });
  }
}

7、activity_displayfile.xml

D:\Apps\ESchoolApp_Debug\platforms\android\app\src\main\res\layout\activity_displayfile.xml
右键New > XML/Layout XML File

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/root_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:theme="@style/Theme.AppCompat">
</RelativeLayout>

8、gradle.properties

D:\Apps\ESchoolApp_Debug\platforms\android\gradle.properties

Android.useDeprecatedNdk=true;

9、js调用插件(务必使用箭头函数,不要使用function)

        cordova.exec(
          success => {
            alert("success = " + success)
          },
          fail => {
            alert("fail = " + fail)
          },
          "X5FileOpen",
          "openFile",
          [filePath, filename]);

10、openFile方法


  /**
   *打开文件
   *
   * @param {*} filePath //文件路径
   * @returns {Promise<any>}
   * @memberof FileProvider
   */
  openFile(filePath): Promise<any> {
    let fileSuffix = PubFunction.GetFileSuffix(filePath);
    let mime = PubFunction.getFileMimeType(fileSuffix);
    return new Promise((r, j) => {
      if (this.plat.is("android")) {
        if(["jpg", "gif", "png"].indexOf(fileSuffix)>=0){
          this.fileOpener.open(filePath, mime)
          .then((entry) => {
            r(entry);
          })
        }else{
          let filename = PubFunction.getFileName(filePath);
          cordova.exec(
            success => {
              // alert("success = " + success);
              r();
            },
            fail => {
              // alert("fail = " + fail);
              this.popupUtil.Alert("提示", fail);
            },
            "X5FileOpen",
            "openFile",
            [filePath, filename]);
        }
      } else if (this.plat.is("ios")) {
        this.fileOpener.open(filePath, mime)
          .then((entry) => {
            r(entry);
          })
          .catch((err: any) => {
            this.popupUtil.Alert("提示", "打开文件失败,请安装支持此文件的应用");
          });
      }
    })
  }

MyX5TbsPlusDemo【体验腾讯浏览服务Android SDK (TbsPlus 版)】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268