cordova插件之下載文件並打開

補充更新

cordova-plugin-file-opener2插件在android@7.0.0上會報編譯錯誤,換成cordova-plugin-vha-fileopener2便可javascript

前言

近期混合app項目中有文件預覽的需求,因文件較多並涉及office、視頻等文件格式,採用第三方app打開方案。
實現過程當中出現一些android7.0+/8.0+的兼容性問題,特此記錄。html

採用此預覽方案文件會被先下載到本地,cordova-plugin-file-opener2插件其實能夠直接打開網絡地址來實現預覽,採用此方式是基於如下考慮:java

  1. 避免重複下載(因app中還有下載功能)
  2. 避免有文件格式解析錯誤的狀況,用戶能夠到本地再次進行查看
  3. 下載目錄可控

框架

項目採用cordova + VUE + MintUIandroid

安裝插件

cordova plugin add cordova-plugin-file
cordova plugin add cordova-plugin-file-transfer
cordova plugin add cordova-plugin-file-opener2

eg: cordova-plugin-file-openercordova-plugin-file-opener2這兩個插件均可以打開文件,但cordova-plugin-file-opener2支持cdvfile://協議,兼容android7.0+以上,不會出現文件權限的問題shell

1、確認API環境

採用Cordova開發的應用在運行的時候,Cordova提供的經過HTML5調用Native功能並非當即就能使用的,Cordova框架在讀入HTML5代碼以後,要進行HTML5和Native創建橋接,在未能完成這個橋接的初始的狀況下,是不能調用Native功能的。在Cordova框架中,當這個橋接的初始化完成後,會調用他自身特有的事件,即deviceready事件。瀏覽器

deviceready事件是在每回讀入HTML的時候都會被調用,而不僅是應用啓動時調用。安全

document.addEventListener("deviceready", function () {
    // 如今能夠安全的使用設備API
    console.log('Device is Ready!')
}, false);

2、建立有效的文件路徑

關於路徑的詳細解釋能夠查看文章:
官網API
cordova-plugin-file 文件操做整理系列網絡

使用cordova-plugin-file插件建立有效的文件路徑app

Device Path cordova.file.* AndroidExtraFileSystems r/w? persistent? OS clears private
file:///android_asset/ applicationDirectory assets r N/A N/A Yes
/data/data/<app-id>/ applicationStorageDirectory - r/w N/A N/A Yes
   cache cacheDirectory cache r/w Yes Yes* Yes
   files dataDirectory files r/w Yes No Yes
      Documents documents r/w Yes No Yes
<sdcard>/ externalRootDirectory sdcard r/w Yes No No
   Android/data/<app-id>/ externalApplicationStorageDirectory - r/w Yes No No
      cache externalCacheDirectory cache-external r/w Yes No** No
      files externalDataDirectory files-external r/w Yes No No
  1. 當目標的WebView的客戶(而不是瀏覽器)或本地應用程序(Windows),你不須要在使用持久性存儲使用requestquota。
  2. 在沙盒目錄結構中使用window.requestFileSystem
  3. 獲取或操做系統文件/目錄,可使用window.resolveLocalFileSystemURL

Android7.0+遇到 android.os.FileUriExposedException: file:///storage/emulated.. exposed beyond app through Intent.getData()錯誤時,要使用window.resolveLocalFileSystemURLcordova.file.externalDataDirectory,不要使用沙盒目錄結構框架

/**
 * desc: 建立文件方法
 */
window.resolveLocalFileSystemURL(
  cordova.file.externalDataDirectory,
  function(fs) {
    fs.getFile(
      _this.fileName, // 建立的文件名
      { create: true, exclusive: true },
      // create:建立新文件,exclusive:文件已存在時拋出異常
      function(fileEntry) {
        // 建立成功回調下載方法寫入文件
        _this.downloadFile(fileEntry);
      },
      function(err) {
        // 失敗回調
        // 從新讀取文件並打開
        fs.getFile(
          _this.fileName,
          { create: false },
          function(fileEntry) {
            // 成功讀取文件後調用cordova-plugin-file-opener2插件打開文件
            _this.preView(fileEntry);
          },
          function(err) {
            _this.toast('讀取文件失敗');
          }
        );
      }
    );
  },
  function(error) {
    _this.toast('進入文件系統失敗!');
  }
);

3、下載文件

/**
 * desc: 文件下載方法
 */
function downloadFile(fileEntry) {
  // 初始化進度條並顯示
  // 此處採用mint-ui的Progress組件
  _this.progress = 0;
  _this.showProgress = true;
  //實例化
  let fileTransfer = new FileTransfer();
  //監聽下載進度
  fileTransfer.onprogress = function(e) {
    if (e.lengthComputable) {
      let progress = e.loaded / e.total;
      // 顯示下載進度
      _this.progress = (progress * 100).toFixed(2);
    }
  };
  // 使用fileTransfer.download開始下載
  fileTransfer.download(
    encodeURI(_this.savePath), //uri網絡下載路徑
    fileEntry.toURL(), //文件本地存儲路徑
    function(entry) {
      // 下載完成執行本地預覽
      if (_this.progress > 1 || _this.progress === 1) {
        _this.showProgress = false;
        entry.file(data => {
          _this.preView(fileEntry);
          // 此處data.type能夠直接獲得文件的MIME-TYPE類型
        });
      }
    },
    function(error) {
      _this.toast('下載失敗!');
    }
  );
}

4、打開文件

/**
 * desc: 文件打開方法
 */
function preview(fileEntry){
    // 調用cordova-plugin-file-opener2插件實現用第三方app打開文件
    cordova.plugins.fileOpener2.showOpenWithDialog(
        // 此處必須填寫cdvfile://地址,否則android7.0+會報文件權限錯誤
        fileEntry.toInternalURL(), //文件本地地址轉cdvfile://地址
        fileTypeArr[_this.fileType], //文件類型,這裏我是寫了一個mime-Type類型合集fileTypeArr來調用 
        function onSuccess(data) {
            console.log('成功預覽:' + fileURL);
        },
        function onError(error) {
            _this.toast(
                '出錯!請在' + cordova.file.externalDataDirectory + '目錄下查看'
            );
        }
    );
}

5、Android8.0+打開apk文件權限問題

Android8.0+上打開apk文件時會報錯android.os.FileUriExposedException: file:///storage/emulated/0/test.apk exposed beyond app through Intent.getData()

根據cordova官網提示 在android 8.0+上您的應用程序必須具備ACTION_INSTALL_PACKAGE權限,須要在config.xml添加以下配置:

<platform name="android">
    <config-file parent="/manifest" target="AndroidManifest.xml" xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    </config-file>
</platform>

注意安裝文件的路徑:在Android 7以前,您只能從「外部」分區安裝APK。例如,您能夠從中安裝cordova.file.externalDataDirectory,但不能從中安裝cordova.file.dataDirectory。Android 7+沒有這個限制。

並在AndroidManifest.xml文件中修改SDK版本

<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />

cordova/ionic默認配置16-26 通過屢次試,只支持16-23的sdk 版本。版本再高就報以上錯誤。

結語

至此,Android5.0+已所有兼容。

Android的版本真的是一個大坑,第一次開發混合app被版本搞的焦頭爛額,但願能給各位看官一點幫助~若有疑問,歡迎溝通~

相關文章
相關標籤/搜索