Delphi FMX函数打开本地文件在Android平台上失败了

1 人关注

我需要一个跨平台的函数来打开一个文件,使用在设备上注册的任何应用程序能够打开相关的文件类型,沿着Windows中的WinAPI函数 ShellExecute 的思路。使用我在Stack-overflow上找到的各种代码例子,我最终得到了以下代码,它可以用Delphi 10.3编译。

{$ifdef Android} FMX.Helpers.Android, AndroidAPI.Helpers, AndroidApi.JNI.GraphicsContentViewText, AndroidApi.JNI.Net, AndroidApi.JNI.JavaTypes; {$endif Android} {$ifDef MSWindows} Winapi.ShellAPI, Winapi.Windows; {$endif MSWindows} procedure OpenFile(FilePathname: string; DisplayError: Boolean); const COption= 0; Extension: string; {$ifdef Android} Intent: JIntent; URI: Jnet_Uri; {$endif Android} Result: integer; begin Extension:= LowerCase(ExtractFileExt(FilePathname)); {$ifdef Android} URI := TJnet_Uri.JavaClass.parse(StringToJString('file:///' + FilePathname)); Intent:= TJIntent.Create; Intent.setFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); case COption of 0: Intent.setData(URI); if Extension= '.pdf' then Intent.setDataAndType(URI,StringToJString('application/pdf')) else if Extension= '.txt' then Intent.setDataAndType(URI,StringToJString('text/*')); SharedActivity.startActivity(Intent); except on E: Exception do begin if DisplayError then ShowMessage('Error: ' + E.Message); {$endif Android} {$ifdef MSWindows} Result:= ShellExecute(0, 'Open', PChar(FilePathname), '', '', SW_SHOWNORMAL); {$endif MSWindows}

在安卓9设备上对SD卡上的本地.PDF文件应用此功能,会出现以下异常。

android.os.FileUriExposedException: file:////SDCard/test.pdf exposed 通过Intent.getData()在应用程序之外。

我在StackOverflow上发现了以下解决这个问题的主题。

android.os.FileUriExposedException: file:///storage/emulated/0/test.txt通过Intent.getData()暴露在App之外。

然而,必须声明和使用一个继承自Java类File-provider的类,以便对一个特定的文件或文件夹进行访问,并使其能够被其他应用程序访问,然后将此记录在 AndroidManifest.xml 似乎过于复杂了,特别是考虑到SD卡中的所有文件根据定义都是公开的。

因此,我的问题是。

  • 在Delphi FMX中是否有更简单的方法来处理这个问题? 10.3+?

  • 如果没有,如何在Delphi中创建一个继承自Java类的Object Pascal类?如果能提供一个代码例子就更好了。

  • 从这个帖子的链接中,我找到了Dave Nottage的以下代码。

    procedure OpenPDFA(const AFileName: string);
      LIntent: JIntent;
      LAuthority: JString;
      LUri: Jnet_Uri;
    begin
      LAuthority := StringToJString(JStringToString(TAndroidHelper.Context.getApplicationContext.getPackageName) + '.fileprovider');
      LUri := TJFileProvider.JavaClass.getUriForFile(TAndroidHelper.Context, LAuthority, TJFile.JavaClass.init(StringToJString(AFileName)));
      LIntent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW);
      LIntent.setDataAndType(LUri, StringToJString('application/pdf'));
      LIntent.setFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
      TAndroidHelper.Activity.startActivity(LIntent);
    

    然而,类TJFileProvider在Delphi编译器中被标记为一个未声明的标识符。我代码中的uses列表似乎与Dave Nottage的代码相同。那么,TJFileProvider是在哪里声明的?

    2 个评论
    你不需要声明一个继承自 FileProvider 的类。你可以直接使用FileProvider。在代码中,只需添加一行即可。在清单文件中声明提供者。嗯......在Java中。
    TJFileProvider is located in Androidapi.JNI.Support
    android
    delphi
    firemonkey
    user11935527
    user11935527
    发布于 2019-12-18
    1 个回答
    mesutuk
    mesutuk
    发布于 2022-04-11
    已采纳
    0 人赞同