如何使用新的 FileProvider 共享当前应用的 APK(或其他已安装应用的 APK)?
How to share current app's APK (or of other installed apps) using the new FileProvider?
背景
过去,使用一个简单的命令就可以轻松地将 APK 文件分享给任何你想要的应用:
startActivity(new Intent(Intent.ACTION_SEND,Uri.fromFile(filePath)).setType("*/*"));
问题
如果你的应用程序目标 Android API 24 (Android Nougat) 或更高版本,上面的代码将导致崩溃,由 FileUriExposedException 引起(关于它 here, and an example solution for opening an APK file can be found here) .
这对我来说效果很好,使用下面的代码:
File apkFile = new File(apkFilePathFromSomewhereInExternalStorage);
Intent intent = new Intent(Intent.ACTION_SEND);
Uri fileUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", apkFile);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
但是,问题是我还希望能够共享当前应用的 APK(以及其他已安装的应用)。
为了获取当前应用程序 APK 的路径,我们使用这个:
final PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
File apkFile=new File(packageInfo.applicationInfo.publicSourceDir);
...
所有应用无需任何许可即可访问此 APK,每个已安装应用的 APK 也是如此。
但是当我将此文件与上述代码一起使用以使用 FileProvider 进行共享时,出现此异常:
IllegalArgumentException: Failed to find configured root that contains ...
当我对 APK 使用符号链接文件时也是如此:
File apkFile=new File(packageInfo.applicationInfo.publicSourceDir);
final String fileName = "symlink.apk";
File symLinkFile = new File(getFilesDir(), fileName);
if (!symLinkFile.exists())
symLinkPath = symLinkFile.getAbsolutePath();
createSymLink(symLinkPath, apkFile.getAbsolutePath());
Uri fileUri= FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", symLinkFile);
...
public static boolean createSymLink(String symLinkFilePath, String originalFilePath) {
try {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
Os.symlink(originalFilePath, symLinkFilePath);
return true;
}
final Class<?> libcore = Class.forName("libcore.io.Libcore");
final java.lang.reflect.Field fOs = libcore.getDeclaredField("os");
fOs.setAccessible(true);
final Object os = fOs.get(null);
final java.lang.reflect.Method method = os.getClass().getMethod("symlink", String.class, String.class);
method.invoke(os, originalFilePath, symLinkFilePath);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
我试过的
我尝试使用我认为有用的各种组合来配置 provider_paths.xml 文件,例如以下任意组合:
<external-path name="external_files" path="."/>
<external-path path="Android/data/lb.com.myapplication/" name="files_root" />
<external-path path="." name="external_storage_root" />
<files-path name="files" path="." />
<files-path name="files" path="" />
我还尝试禁用与此机制关联的严格模式:
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
问题
如何从我的应用程序可访问的所有可能路径共享任何 APK 文件,包括使用符号链接文件?
But when I use this file with the above code for sharing using the FileProvider, I get this exception
那是因为 packageInfo.applicationInfo.publicSourceDir
不在 FileProvider
的可能根之一之下。
The same goes for when I use a symlinked file to the APK
也许符号链接在这里不起作用。您的 <files-path>
元素之一 - 或者您完全关闭 path
的元素 - 可以提供来自 getFilesDir()
.
的普通文件
How can I share any APK file, from every possible path that's accessible to my app, including using symlinked files ?
由于没有对符号链接的官方支持,因此我无法为您提供帮助。
否则,您有三个主要选择:
在 FileProvider
喜欢的地方复制 APK 文件
尝试使用 my StreamProvider
和一些自定义扩展来教它从 packageInfo.applicationInfo.publicSourceDir
开始服务
编写您自己的 ContentProvider
,服务于 packageInfo.applicationInfo.publicSourceDir
我记得,apk 文件位于 /data/app/your.package.name-1(or -2)/base.apk since SDK 21 (or 23? Correct me if I is错误的。)。和 /data/app/your.package.name.apk 之前。所以试试这个:
<root-path path="data/app/" name="your.name">
我的回答不适用于您的情况。我在评论区解释了。
PS:正如@CommonsWare 所说,此功能未记录。将来有可能将其删除。所以使用这个是有风险的。
背景
过去,使用一个简单的命令就可以轻松地将 APK 文件分享给任何你想要的应用:
startActivity(new Intent(Intent.ACTION_SEND,Uri.fromFile(filePath)).setType("*/*"));
问题
如果你的应用程序目标 Android API 24 (Android Nougat) 或更高版本,上面的代码将导致崩溃,由 FileUriExposedException 引起(关于它 here, and an example solution for opening an APK file can be found here) .
这对我来说效果很好,使用下面的代码:
File apkFile = new File(apkFilePathFromSomewhereInExternalStorage);
Intent intent = new Intent(Intent.ACTION_SEND);
Uri fileUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", apkFile);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
但是,问题是我还希望能够共享当前应用的 APK(以及其他已安装的应用)。
为了获取当前应用程序 APK 的路径,我们使用这个:
final PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
File apkFile=new File(packageInfo.applicationInfo.publicSourceDir);
...
所有应用无需任何许可即可访问此 APK,每个已安装应用的 APK 也是如此。
但是当我将此文件与上述代码一起使用以使用 FileProvider 进行共享时,出现此异常:
IllegalArgumentException: Failed to find configured root that contains ...
当我对 APK 使用符号链接文件时也是如此:
File apkFile=new File(packageInfo.applicationInfo.publicSourceDir);
final String fileName = "symlink.apk";
File symLinkFile = new File(getFilesDir(), fileName);
if (!symLinkFile.exists())
symLinkPath = symLinkFile.getAbsolutePath();
createSymLink(symLinkPath, apkFile.getAbsolutePath());
Uri fileUri= FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", symLinkFile);
...
public static boolean createSymLink(String symLinkFilePath, String originalFilePath) {
try {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
Os.symlink(originalFilePath, symLinkFilePath);
return true;
}
final Class<?> libcore = Class.forName("libcore.io.Libcore");
final java.lang.reflect.Field fOs = libcore.getDeclaredField("os");
fOs.setAccessible(true);
final Object os = fOs.get(null);
final java.lang.reflect.Method method = os.getClass().getMethod("symlink", String.class, String.class);
method.invoke(os, originalFilePath, symLinkFilePath);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
我试过的
我尝试使用我认为有用的各种组合来配置 provider_paths.xml 文件,例如以下任意组合:
<external-path name="external_files" path="."/>
<external-path path="Android/data/lb.com.myapplication/" name="files_root" />
<external-path path="." name="external_storage_root" />
<files-path name="files" path="." />
<files-path name="files" path="" />
我还尝试禁用与此机制关联的严格模式:
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
问题
如何从我的应用程序可访问的所有可能路径共享任何 APK 文件,包括使用符号链接文件?
But when I use this file with the above code for sharing using the FileProvider, I get this exception
那是因为 packageInfo.applicationInfo.publicSourceDir
不在 FileProvider
的可能根之一之下。
The same goes for when I use a symlinked file to the APK
也许符号链接在这里不起作用。您的 <files-path>
元素之一 - 或者您完全关闭 path
的元素 - 可以提供来自 getFilesDir()
.
How can I share any APK file, from every possible path that's accessible to my app, including using symlinked files ?
由于没有对符号链接的官方支持,因此我无法为您提供帮助。
否则,您有三个主要选择:
在
FileProvider
喜欢的地方复制 APK 文件尝试使用 my
StreamProvider
和一些自定义扩展来教它从packageInfo.applicationInfo.publicSourceDir
开始服务
编写您自己的
ContentProvider
,服务于packageInfo.applicationInfo.publicSourceDir
我记得,apk 文件位于 /data/app/your.package.name-1(or -2)/base.apk since SDK 21 (or 23? Correct me if I is错误的。)。和 /data/app/your.package.name.apk 之前。所以试试这个:
<root-path path="data/app/" name="your.name">
我的回答
PS:正如@CommonsWare 所说,此功能未记录。将来有可能将其删除。所以使用这个是有风险的。