Android专家......我处在一个quardry中。我有一个嵌入在Forms应用程序中的WebView,它还具有为其实现的自定义渲染器(用于WebView)。
我正在包装一个基本的网络应用程序(SAP Fiori),并且在该应用程序中,它有一个工资声明部分,用户可以在其中查看他们的工资单。在该页面上,有一个按钮可将付款单下载到PDF。
在我的应用程序的iOS中,这一切都是标准的,即PDF打开并在浏览器中查看。在Android和iOS上,任何浏览器(如Chrome或Safari)都可以正常工作。
在我的Android应用中,点击"以PDF格式打开"按钮没有结果,前端没有任何事情发生但在应用程序本身内,触发了实现的DownloadListener方法......
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);
}
}
这些是主要的DownloadEventArgs值...
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"
...现在,在该网址后面,有一段javascript会生成动态PDF,因此它不会存储在服务器上的任何位置,这就是我似乎遇到问题的地方。
我在网上阅读的所有内容都说使用HttpClient将PDF的内容下载到文件然后打开它。但是,如果我将该URL传递给HttpClient,我无法获取PDF数据,我会收到HTML文本。
我在StackOverflow上尝试了GoogleDocs和许多其他链接,但无论我做什么,该URL都会返回HTML文本,而不是PDF文档的内容。
我几乎无法控制SAP给我的东西,所以更改服务器端是不太可能的选择。
非常感谢任何帮助。
答案 0 :(得分:0)
不幸的是,由于某些原因,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 :(得分:0)
您可以通过两种解决方案来做到这一点:
解决方案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>
在Xamarin.Android项目的Resources文件夹内的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>