Предисловие: я использую C # с Xamarin, но рабочий процесс такой же.
Я хочу открывать / отображать (в автономном режиме) файлы HTML (которые связаны с другими файлами HTML, CSS и JavaScript) в браузере на Android. Это 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):
[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?