使用范围存储将文件加载到 webView

Load file into webView with scoped storage

我通过自定义 webview 在我的应用程序中显示 pdf 文件和图像,它显示了一个位于我的应用程序资产文件夹中的 html 小站点。这个“主页”通过获取参数获取要显示的文件。要显示的文件位于我的私人应用程序文档文件夹中。 在我必须将目标 API 级别 30 或更高级别(强制使用范围存储)之前,这工作得很好。现在“主页”无法访问私人文档文件夹中的文件(访问冲突)。 我想知道是否有办法仍然使用这种方法,通过启用了范围存储的 webview 在您的应用程序中显示 pdf 文件和图像。

以下是其当前实施方式的详细信息:

在自定义 webview 的 android 渲染器的 OnElementChanged 方法中(使用 Uri 属性 扩展 Xamarin.Forms.WebView)我设置了 Android webView( control),然后加载uri到图片首页或pdf.js webviewer,在uri中获取参数中的文件(图片或pdf):

protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                var customWebView = Element as CustomWebView;
                Control.Settings.AllowUniversalAccessFromFileURLs = true;
                Control.Settings.SetSupportZoom(true);
                Control.Settings.BuiltInZoomControls = true;
                Control.Settings.DisplayZoomControls = true;


                int width = MainApplication.intWidth;
                string PathCopy = customWebView.Uri;
                customWebView.Uri = customWebView.Uri.Replace(" ", "%20");

                string Extension = Path.GetExtension(WebUtility.UrlEncode(customWebView.Uri)).ToUpper();

                switch (Extension)
                {
                    case ".PDF": Control.LoadUrl(string.Format("file:///android_asset/pdfjs/web/viewer.html?file={0}", WebUtility.UrlEncode(customWebView.Uri))); break;
                    default: Control.LoadUrl(string.Format("file:///android_asset/ImageHomepage/ImageHomepage.html?pfad={0}&width={1}", customWebView.Uri, width)); break;
                }
            }
        }

对于 pdf 文件,我使用 pdf.js(如本例所示:https://github.com/xamarin/docs-archive/tree/master/Recipes/xamarin-forms/Controls/display-pdf),对于图像,我使用 html 这个小网站:

<head>
<script> 
function getURLParameter(name)
{
    var value = decodeURIComponent((RegExp(name + '=' + '(.+?)(&|$)').exec(location.search) || [, ""])[1]);
    return (value !== 'null') ? value : false;
}
</script>
</head>

<body>

<script language = "Javascript" type="text/javascript">
<!--
var param = getURLParameter('pfad');
var width = getURLParameter('width');

document.write('<img src="');document.write(param); document.write('" width="'); document.write(width); document.write('" style="width:100%" >'); 
//-->

</script>
</body>

要显示的文件是从我的网络服务下载并存储在我的“PrivateDocumentsFolder”中,声明如下:

public static string PrivateFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public static string PrivateDocumentsFolder = Path.Combine(PrivateFolder, "Dokumente");

所以文件存储在:/data/user/0/myPackageName/files/Dokumente,这是我在访问 [=38] 的 FilesDir 属性 时也得到的私人文件夹=]上下文对象。

将 requestLegacyExternalStorage 设置为 true 的目标 API 29 使用此方法。使用 Xamarin.Essentials Launcher 打开文件可以启用分区存储,但我想继续在我的应用程序中而不是在外部应用程序中显示文件。

如何在 API 级别 >29 并启用分区存储的情况下使用此方法? 如果我理解正确,使用 Environment.SpecialFolder.MyDocuments 应该是正确的方法,因为它在我的应用程序私有范围内,从我的应用程序内部访问这些文件应该没有问题。

首先,您授予读写存储权限了吗?该文件位于应用程序的私人文件夹中。一般情况下,app可以直接访问。

此外,如果用户更新到API 30,您可以使用preserveLegacyExternalStorage=trueandroid:requestLegacyExternalStorage=true来保留和使用旧的存储模型。

最后,您可以添加一些 WebView 设置的更改。如:

 Control.Settings.AllowFileAccess = true;

对于api29,默认值为true。而 api 30 是假的。

可以查看官方文档: https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess(boolean)