Отправить несколько URI в браузер (открыть файлы HTML из внутреннего хранилища с помощью FileProvider) - PullRequest
0 голосов
/ 27 апреля 2018

Предисловие: я использую 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?

...