我们如何在 Android 的 Cordova.inappbrowser 中显示基于 64 位字符串的 PDF

Posted

技术标签:

【中文标题】我们如何在 Android 的 Cordova.inappbrowser 中显示基于 64 位字符串的 PDF【英文标题】:how can we display the PDF from base 64 string in Cordova.inappbrowser in Android 【发布时间】:2019-03-02 00:44:56 【问题描述】:

我的要求是在 cordova.InAppBrowser 中显示 pdf base64 字符串,它没有在 android 中显示

但它显示在 ios 应用程序中。 我正在使用下面的代码在 InAppBrowser 中显示 PDF

$scope.urlString = "data:application/pdf;base64,"+encodeURI($scope.PdfString);
var ref = cordova.InAppBrowser.open($scope.urlString, '_blank',  'toolbarposition=bottom');

有人知道如何在 Cordova InAppBrowser 中显示 PDF base64 字符串吗?或者有没有其他的显示方式。

【问题讨论】:

【参考方案1】:

终于解决了 我们的项目中需要有cordova-file-plugin

cordova 插件添加cordova-plugin-file

var myBase64 = "JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwogIC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAvTWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0KPj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAgL1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9udAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2JqCgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJUCjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVuZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4gCjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAwMDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9vdCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G";
// To define the type of the Blob
var contentType = "application/pdf";
// if cordova.file is not available use instead :
// var folderpath = "file:///storage/emulated/0/";
var folderpath = cordova.file.externalRootDirectory;
    var filename = "helloWorld.pdf";

    savebase64AsPDF(folderpath,filename,$scope.PdfString,contentType);

function b64toBlob(b64Data, contentType, sliceSize) 
        contentType = contentType || '';
        sliceSize = sliceSize || 512;
        var byteCharacters = atob(b64Data);
        var byteArrays = [];
        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) 
            var slice = byteCharacters.slice(offset, offset + sliceSize);
            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) 
                byteNumbers[i] = slice.charCodeAt(i);
            
            var byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        
      var blob = new Blob(byteArrays, type: contentType);
      return blob;

    function savebase64AsPDF(folderpath,filename,content,contentType)
        // Convert the base64 string in a Blob
        var DataBlob = b64toBlob(content,contentType);

        console.log("Starting to write the file :3");

        window.resolveLocalFileSystemURL(folderpath, function(dir) 
            console.log("Access to the directory granted succesfully");
    		dir.getFile(filename, create:true, function(file) 
                console.log("File created succesfully.");
                file.createWriter(function(fileWriter) 
                    console.log("Writing content to file");
                    fileWriter.write(DataBlob);
                    console.log("Folder Path"+folderpath+filename);
                    var finalPath = folderpath+filename;
                     window.open(finalPath, '_system');

                , function()
                    alert('Unable to save file in path '+ folderpath);
                );
    		);
        );
    

【讨论】:

此代码仅适用于 Android,是否适用于 iOS?【参考方案2】:

为了补充@Byka 的解决方案,我们应该在 ionic 3 中安装它

    ionic cordova 插件添加cordova-plugin-file npm install --save @ionic-native/file ionic cordova 插件添加 cordova-plugin-file-opener2 npm install --save @ionic-native/file-opener

重要的是,由于某种原因,文件中的 writeFile 不起作用,因此请编辑您的 index.html

你应该在你的 cordova.js 之前包含

      <script src="build/polyfills.js"></script>

将插件添加到您应用的模块中

从“@ionic-native/file”导入文件 从 '@ionic-native/file-opener' 导入 FileOpener

也添加到提供程序中

提供者:[ ...... 文件, 文件打开器 ]

import  Component  from '@angular/core'
import  NavController, NavParams, Platform  from 'ionic-angular'
import  InAppBrowser  from '@ionic-native/in-app-browser'
import  File  from '@ionic-native/file'
import  FileOpener  from '@ionic-native/file-opener'

@Component(
  selector: 'page-pantalla-mi-promenal-consultas',
  templateUrl: 'pantalla-mi-promenal-consultas.html'
)
export class YourPage 
 

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private platform: Platform,
    private file: File,
    private fileOpener: FileOpener
  ) 

  getUserDataSheet() 
          const blob = this.b64toBlob(pdfString, 'application/pdf', 512)
          let pathFile = ''
          const fileName = 'myPdf.pdf'
          const contentFile = blob
          if (this.platform.is('ios')) 
            pathFile = this.file.documentsDirectory
           else 
            pathFile = this.file.externalRootDirectory
          
          this.file
            .writeFile(pathFile, fileName, contentFile,  replace: true )
            .then(success => 
              this.fileOpener
                .open(pathFile + fileName, 'application/pdf')
                .then(data => 
                  this.inAppBrowser.create(data, '_system')
                )
                .catch(e => console.log('Error opening file', e))
            )
            .catch(e => console.log('Error writing file', e))
        
  

  b64toBlob(b64Data, contentType, sliceSize = 512) 
    contentType = contentType || ''
    sliceSize = sliceSize || 512
    b64Data = b64Data.replace(/^[^,]+,/, '')
    b64Data = b64Data.replace(/\s/g, '')

    var byteCharacters = atob(b64Data)
    var byteArrays = []

    for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) 
      var slice = byteCharacters.slice(offset, offset + sliceSize)

      var byteNumbers = new Array(slice.length)
      for (var i = 0; i < slice.length; i++) 
        byteNumbers[i] = slice.charCodeAt(i)
      

      var byteArray = new Uint8Array(byteNumbers)

      byteArrays.push(byteArray)
    

    var blob = new Blob(byteArrays, 
      type: contentType
    )
    // return byteCharacters;
    return blob
  

【讨论】:

【参考方案3】:

就我而言,Byka 的答案仅适用于 Android。 我对其进行了编辑,现在它在 iOS 中也像魅力一样工作。 我的应用程序下载一个 pdf base64 编码,转换并打开它。

问题是在iOS中打开文件,添加file opener2 plugin解决了

function b64toBlob(b64Data, contentType, sliceSize) 
    contentType = contentType || '';
    sliceSize = sliceSize || 512;
    var byteCharacters = atob(b64Data);
    var byteArrays = [];
    for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) 
        var slice = byteCharacters.slice(offset, offset + sliceSize);
        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) 
            byteNumbers[i] = slice.charCodeAt(i);
        
        var byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
    
    var blob = new Blob(byteArrays,  type: contentType );
    return blob;


function savebase64AsPDF(folderpath, filename, content, contentType) 
    // Convert the base64 string in a Blob
    var DataBlob = b64toBlob(content, contentType);
    window.resolveLocalFileSystemURL(folderpath, function (dir) 
        dir.getFile(filename,  create: true , function (file) 
            file.createWriter(function (fileWriter) 
                fileWriter.write(DataBlob);
                var finalPath = folderpath + filename;
                //window.open(finalPath, '_system');
                cordova.plugins.fileOpener2.open(finalPath, 'application/pdf'
                    //,
                    //
                    //    error: function (e) 
                    //        alert('Error status: ' + e.status + ' - Error message: ' + e.message);
                    //    ,
                    //    success: function () 
                    //        alert('file opened successfully');
                    //    
                    //
            );

            , function () 
                alert("err");
        );
    );


function PrintFile(id) 
            jQuery("#large-indicator").css("display", "inline");
            $.ajax(
                type: "POST",
                contentType: "application/json",
                dataType: "json",
                url: "myurl",
                data: JSON.stringify(
                    "id": id
                ),
                success: function (Response) 
                    jQuery("#large-indicator").css("display", "none");
                    var contentType = "application/pdf";
                    var folderpath = cordova.file.externalRootDirectory;
                    if (folderpath == null)
                        folderpath = cordova.file.dataDirectory
                    var filename = id + ".pdf";
                    savebase64AsPDF(folderpath, filename, Response.value, contentType);
                ,
                error: function (Response) 
                    jQuery("#large-indicator").css("display", "none");
                    var mex = Response["responseText"];
                    alert(mex);
                
            );

【讨论】:

【参考方案4】:

这就是我在 Android 和 IOS 上实现的方式。 干杯!!

使用这个插件

<plugin name="cordova-plugin-inappbrowser" />
<plugin name="cordova-plugin-file"/>
<plugin name="cordova-plugin-file-transfer"/>
<plugin spec="https://github.com/tectronik/cordova-plugin-file-opener2-tectronik.git"/>

适合您的工作代码。

    var blob = b64toBlob("base64 string here", 'application/pdf');
    var pathFile = "";
    var fileName ='PdfName.pdf';
    var contentFile = blob;
    if (ionic.Platform.isIOS()) 
        var pathFile = cordova.file.documentsDirectory
     else 
        var pathFile = cordova.file.externalRootDirectory
    

    $cordovaFile.writeFile(pathFile, fileName, contentFile, true)
        .then(function(success) 
            $scope.filePath=pathFile + fileName;
            // console.log("File saved on internal storage location," + pathFile + fileName);

        if (ionic.Platform.isAndroid()) 
            $cordovaFileOpener2.open($scope.filePath,
                'application/pdf'
                ).then(function() 
                    // file opened successfully
                    // alert(' file opened successfully')
                , function(err) 
                    alert('An error occurred '+err);
                );
        else
            var ref = cordova.InAppBrowser.open(data, '_blank', 
    'location=no,toolbar=yes');
            
, function(error) 

); 
function b64toBlob(b64Data, contentType, sliceSize) 
        contentType = contentType || '';
        sliceSize = sliceSize || 512;

        b64Data = b64Data.replace(/^[^,]+,/, '');
        b64Data = b64Data.replace(/\s/g, '');

        var byteCharacters = atob(b64Data);
        var byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) 
            var slice = byteCharacters.slice(offset, offset + sliceSize);

            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) 
                byteNumbers[i] = slice.charCodeAt(i);
            

            var byteArray = new Uint8Array(byteNumbers);

            byteArrays.push(byteArray);
        

        var blob = new Blob(byteArrays, 
            type: contentType
        );
        // return byteCharacters;
        return blob;
    

【讨论】:

谢谢。当我在 Cordova Android 中运行此代码时,它会显示错误“ReferenceError:cordovaFile 未定义”我已经安装了插件 github.com/tectronik/…> 你需要安装 ==>> cordova-plugin-file 我安装了两个插件 cordova-plugin-file 6.0.1 "File" cordova-plugin-file-opener2 2.0.19 "File Opener2" 我已经发布了工作代码。但没有得到你做错了什么。 也添加这个插件试试

以上是关于我们如何在 Android 的 Cordova.inappbrowser 中显示基于 64 位字符串的 PDF的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在android中将隐藏的布局从屏幕底部滑动到中间屏幕?

我们如何在 Android 中使用 FirestoreRecyclerAdapter 实现基于日期的文档分组

我们如何在 firebase(android、kotlin)中记录错误?

如何让我们的应用在 android 的“打开方式”中可见?

我们如何在我们的 android 应用程序中执行一个 javascript 函数并获得一个返回值?

我们如何在 android 的 RecyclerView 片段中使用 bottomSheet?