前言:我使用C#和Xamarin,但工作流程是一样的。
我想在Android上的浏览器中打开/显示(离线)HTML文件(与其他HTML,CSS和JavaScript文件链接)。这是index.html
:
<!DOCTYPE html>
<html data-mc-runtime-file-type="Default" class="_Skins_HTML5___Top_Navigation">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><title></title>
<script type="text/javascript" src="Resources/Scripts/custom.modernizr.js">
</script>
<script type="text/javascript" src="Resources/Scripts/jquery.min.js">
</script>
<script type="text/javascript" src="Resources/Scripts/plugins.min.js">
</script>
<script type="text/javascript" src="Resources/Scripts/require.min.js">
</script>
<script type="text/javascript" src="Resources/Scripts/require.config.js">
</script>
<script type="text/javascript" src="Resources/Scripts/MadCapAll.js">
</script>
</head>
<body>
</body>
</html>
这些文件位于内部应用存储空间/data/data/com.xxx.xxx/files/help
中,它们位于不同的子文件夹中,如下所示:
drwxrwxr-x 4 root root 4096 2018-04-26 09:22 Content
drwxrwxr-x 2 root root 4096 2018-04-26 09:22 Data
-rw-rw-rw- 1 root root 11327 2018-01-12 17:24 HTML5 - Top Navigation.mclog
drwxrwxr-x 3 root root 4096 2018-04-26 09:22 Resources
drwxrwxr-x 4 root root 4096 2018-04-26 09:22 Skins
-rw-rw-rw- 1 root root 344798 2018-01-12 17:24 csh.js
-rw-rw-rw- 1 root root 951 2018-01-12 17:24 index.html
-rw-rw-rw- 1 root root 348211 2018-01-12 17:24 index.js
-rw-rw-rw- 1 root root 1269 2018-01-12 17:24 index.mcwebhelp
-rw-rw-rw- 1 root root 2622 2018-01-12 17:24 index_CSH.html
我正在使用FileProvider(类似于Android Manifest中定义的):
[ContentProvider(new[] { "${applicationId}.html.fileprovider" }, Name = "com.xxx.xxx.HelpFileProvider", GrantUriPermissions = true, Exported = false)]
[MetaData("android.support.FILE_PROVIDER_PATHS", Resource = "@xml/help_html_provider_paths")]
class HelpFileProvider : FileProvider
{
}
我在XML文件(help_html_provider_paths.xml
)中添加了路径:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="help" path="help/"/>
</paths>
要从应用程序外部打开index.html文件,需要创建一个Uri:
Android.Net.Uri contentUri = FileProvider.GetUriForFile(_context, _context.PackageName + ".html.fileprovider", newFile);
但仅限于index.html,试图打开它会导致空白屏幕和以下错误(其中多个):
01-01 01:36:38.096 E/DatabaseUtils( 4924): Writing exception to parcel
01-01 01:36:38.096 E/DatabaseUtils( 4924): java.lang.SecurityException: Permission Denial: reading com.xxx.xxx.HelpFileProvider uri content://com.xxx.xxx.html.fileprovider/help/Resources/Scripts/jquery.min.js from pid=4989, uid=10052 requires the provider be exported, or grantUriPermission()
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:608)
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:483)
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:474)
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:419)
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:313)
01-01 01:36:38.096 E/DatabaseUtils( 4924): at android.os.Binder.execTransact(Binder.java:565)
我知道 - 这意味着其他文件无法打开,因为它们没有URI,只有index.html。
然后我尝试了不同的方法(获取所有文件URI并使用ClipData发送它们)没有成功,如下所示:
public void OpenHtml(string directory, string file) // "PATH/TO/help/" and "index.html"
{
try
{
Java.IO.File filePath = new File(_context.FilesDir.AbsolutePath, directory);
Java.IO.File newFile = new File(filePath, file);
List<File> allFiles = new List<File>();
Listfiles(filePath.AbsolutePath, allFiles); // Get recursiv all files from each subfolder
Android.Net.Uri contentUri = FileProvider.GetUriForFile(_context, _context.PackageName + ".html.fileprovider", newFile);
ClipData clipData = ClipData.NewUri(_context.ContentResolver, "com.xxx.xxx", contentUri);
allFiles.ForEach(file1 =>
{
Android.Net.Uri uri = FileProvider.GetUriForFile(_context, _context.PackageName + ".html.fileprovider", file1);
clipData.AddItem(new ClipData.Item(uri));
});
var intent = new Intent(Intent.ActionView, contentUri);
intent.ClipData = clipData;
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
_context.StartActivity(intent);
}
catch (ActivityNotFoundException ex)
{
Logger.Error("No Browser installed!!", ex);
throw new ApplicationException();
}
catch (Exception ex)
{
Logger.Error("Failed to display html", ex);
}
}
我忘了什么吗?或者这种特殊情况是不可能的,因为html文件中的链接与URI不匹配?