Xamarin Android WebView下载Inline PDF内容



android专家...我正在搜索灾难。我有一个嵌入在表单应用中的Webview,该应用程序还具有为其实现的自定义渲染器(用于WebView(。

我正在包装一个基本的Web应用程序(SAP Fiori(,在该应用程序中,它有一个薪水声明部分,用户可以在其中查看其工资单。在该页面上,有一个按钮可以下载薪水。

在我的应用程序中的iOS中,所有这些都可以作为标准化,即PDF打开并在浏览器中查看。在Android和iOS上,任何浏览器(例如Chrome或Safari(也可以正常工作。

在我的Android应用中,单击"打开为PDF"按钮不会产生结果,前端什么也没有发生,但是在应用程序本身中,实现的下载列表方法是触发的...

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged(e);
        Control.Settings.AllowUniversalAccessFromFileURLs = true;
        Control.SetWebViewClient(new MySAPWebViewClient(Context));
        Control.SetDownloadListener(new MySAPDownloadListener());
    }
public class MySAPDownloadListener : Java.Lang.Object, IDownloadListener
{
    public new void Dispose() { }
    public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength)
    {
        System.Diagnostics.Debug.WriteLine("Url = " + url);
        System.Diagnostics.Debug.WriteLine("Content Disposition = " + contentDisposition);
        System.Diagnostics.Debug.WriteLine("Mime Type = " + mimetype);
    }
}

这些是主要的下loadeventargs值...

url = "https://organisation.com/sap/opu/odata/sap/HCM_MY_PAYSTUBS_SRV/PDFPaystubs(SEQUENCENUMBER=189,PersonnelAssignment='00044411')/$value"
contentDisposition = "inline; filename=Paystub_01.31.2018.pdf"
mimetype = "application/pdf"

...现在,在该URL后面,有一块JavaScript生成动态PDF,因此它没有存储在服务器上的任何地方,这似乎是我遇到问题的地方。

我在线阅读的所有内容都说要使用httpclient下载pdf的内容以归档,然后将其打开。但是,如果我将该URL传递给HTTPCLIENT,我没有得到PDF数据,我会得到HTML文本。

我在Stackoverflow上尝试了GoogleDocs和许多其他链接,但是无论我做什么,URL都返回HTML文本,而不是PDF文档的内容。

我对SAP也给我的东西几乎没有控制权,因此更改服务器端是一个不太可能的选择。

任何帮助都将不胜感激。

您可以通过两个解决方案来执行此操作:

解决方案1:在系统默认浏览器中打开URL。

private async Task MWebview_Download(object sender, DownloadEventArgs e)
{
    await Launcher.OpenAsync(e.Url);               
}

解决方案2 使用httpclient下载。

    private async void MWebview_Download(object sender, DownloadEventArgs e)
    {
        string fileName = GetFileName(e);
        Device.BeginInvokeOnMainThread(() =>
        {
            Toast.MakeText(MainActivity.Instance, "Downloading File...", ToastLength.Long).Show();
        });

        await DownloadPdfFile(e, fileName);
    }
    private async Task DownloadPdfFile(DownloadEventArgs e, string fileName)
    {
        try
        {
            //Bypass the certificate 
            HttpClientHandler clientHandler = new HttpClientHandler();
            clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
            // Getting Cookie
            String cookies = CookieManager.Instance.GetCookie(e.Url);
            var client = new HttpClient(clientHandler);
            var httpRequestMessage = new HttpRequestMessage
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri(e.Url),
                Headers = {
                { HttpRequestHeader.TransferEncoding.ToString(), "binary" },
                { HttpRequestHeader.ContentLength.ToString(), e.ContentLength+"" },
                { HttpRequestHeader.ContentType.ToString(), "application/pdf" },
                {HttpRequestHeader.Cookie.ToString(),cookies },
            },
            };
            // Api Call
            var response = await client.SendAsync(httpRequestMessage);
            // Read content as Byte[]
            var bytes = response.Content.ReadAsByteArrayAsync().Result;
            // Save to Local DB
            var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
            var filePath = Path.Combine(documentsPath, fileName);
            // convert byte to stream
            MemoryStream stream = new MemoryStream(bytes);
            // Write file
            SaveAndView(fileName, "application/pdf", stream);
        }
        catch (Exception ee)
        {
            Toast.MakeText(MainActivity.Instance, "Failed !!", ToastLength.Long).Show();
        }
    }
    public void SaveAndView(string fileName, String contentType, MemoryStream stream)
    {
        string exception = string.Empty;
        string root = null;
        if (ContextCompat.CheckSelfPermission(MainActivity.Instance, Manifest.Permission.WriteExternalStorage) != Permission.Granted)
        {
            ActivityCompat.RequestPermissions((Activity)MainActivity.Instance, new String[] { Manifest.Permission.WriteExternalStorage }, 1);
        }
        if (Android.OS.Environment.IsExternalStorageEmulated)
        {
            root = Android.OS.Environment.ExternalStorageDirectory.ToString();
        }
        else
            root = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
        Java.IO.File myDir = new Java.IO.File(root + "/PDFFiles");
        myDir.Mkdir();
        Java.IO.File file = new Java.IO.File(myDir, fileName);
        if (file.Exists()) file.Delete();
        try
        {
            FileOutputStream outs = new FileOutputStream(file);
            outs.Write(stream.ToArray());
            outs.Flush();
            outs.Close();
        }
        catch (Exception e)
        {
            exception = e.ToString();
        }
        if (file.Exists() && contentType != "application/html")
        {
            string extension = MimeTypeMap.GetFileExtensionFromUrl(Android.Net.Uri.FromFile(file).ToString());
            string mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
            Intent intent = new Intent(Intent.ActionView);
            intent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.NewTask);
            Android.Net.Uri path = FileProvider.GetUriForFile(MainActivity.Instance, Android.App.Application.Context.PackageName + ".provider", file);
            intent.SetDataAndType(path, mimeType);
            intent.AddFlags(ActivityFlags.GrantReadUriPermission);
            MainActivity.Instance.StartActivity(Intent.CreateChooser(intent, "Choose App"));
        }
    }

注意:确保处理FileProvider:

 **Changes in Manifest file:** 
   - Add android:requestLegacyExternalStorage="true" in application tag
   
   - Add between application tag
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false" android:grantUriPermissions="true">
          <meta-data
             android:name="android.support.FILE_PROVIDER_PATHS"
             android:resource="@xml/file_paths" />
    </provider>

添加XMARIN.ANDROID项目中的XML文件夹中的file_paths.xml。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <external-files-path name="my_images" path="Pictures" />
   <external-files-path name="my_movies" path="Movies" />
   <external-path name="external_files" path="."/>
</paths>     

不幸的是,由于某些原因,Android WebView无法显示PDF文件。因此,如果使用WebView对您至关重要,那么只有一个选项 - 使用Google Docs Viewer。但这仅适用于通过公共URL提供的PDF。它看起来像这样:

 WebView view=(WebView)findViewById(R.id.webView);
 view.setWebViewClient(new WebViewClient());
 String url=getIntent().toString("value1");
 String URL="https://docs.google.com/viewer?url="+url; 
 view.loadUrl(Url);

如果使用WebView不是那么重要,则可以使用:

  1. 一些第三方库显示PDF
  2. 致电通过另一个应用显示PDF的意图
  3. 如果您使用API级别21及以上 - 您可以用Android PDFrenderer弄脏手

希望它能帮助

最新更新