【问题标题】:Can We Install an APK From a ContentProvider?我们可以从 ContentProvider 安装 APK 吗?
【发布时间】:2012-03-09 16:34:02
【问题描述】:

我正在开发a library to allow apps to self-update,用于那些在 Android Market 之外分发的产品。

我最初的计划是包含将 APK 文件下载到内部存储的代码,然后通过 ContentProvidercontent:// Uri 从那里安装它。但是,当我尝试这样做时,安装程​​序系统向 LogCat 转储了“Skipping dir:”警告并且未能实际安装它。一旦我切换到将 APK 下载到外部存储并使用 file:// UriACTION_VIEW 安装程序 Intent,它就可以工作了。

“跳过目录:”消息似乎由parsePackage()PackageParser 中记录,这似乎假设它正在使用File。这表明我们不能使用 content:// Uri 值。

有没有人在application/vnd.android.package-archive Intentcontent:// Uri 上成功使用ACTION_VIEW?如果是这样,在设置 ContentProvider 时是否有一些特定的技巧使它起作用?

谢谢!

【问题讨论】:

  • 这个 ContentProvider 的外观如何(特别是 openFile 实现)?
  • @Selvin:ContentProvideropenFile() 实现是允许提供文件所需要的,我使用an existing trivial implementation that I know works in general 作为基础。我的问题是是否有人成功地让它工作,因为我对源代码的阅读表明它不受支持,无论 ContentProvider 看起来如何。
  • 我没试过,但是你看到这里描述的方法了吗:stackoverflow.com/a/4605040/377260
  • @iPaulPro:只有在构建固件时才有效。

标签: android


【解决方案1】:

ACTION_INSTALL_PACKAGE 的文档不正确。它也只会接受文件。

因此,我唯一的建议是在应用程序文件区域中创建该文件的副本,使其全球可读,并在以后清理所有剩余文件。

上一个错误答案:在 4.0 及更高版本中有一个 ACTION_INSTALL_PACKAGE 将接受 content:// URI (JavaDoc),但在此之前,您只能通过以下方式安装 ACTION_VIEW 假定传递的 URI 是 file:// URI。

【讨论】:

  • 你试过了吗?当我使用content:// 方案时,我得到与ACTION_VIEW 相同的结果——“跳过目录”LogCat 消息,安装程序退出。
  • 我相信文档,但文档似乎是错误的。服务 ACTION_INSTALL_PACKAGE 的代码也将只接受文件。是时候注册一个错误了。对不起。
  • 好吧,那么至少我还没有完全疯掉。完全疯狂,当然。 :-) 感谢您的帮助!
  • 注意:content 方案适用于 Android 7.0,但不适用于早期版本的 Android。
  • 重要 - Context.MODE_WORLD_READABLE 已弃用并且(来自文档:)“从 [Android] N 开始,尝试使用此模式将引发 SecurityException”。我使用Context.MODE_WORLD_READABLE 让系统访问应用程序私有存储目录​​中下载的 APK 文件,因此我不需要外部存储权限,但从 Android 7 开始,这不再可能!
【解决方案2】:

我认为这是不可能的,因为 Java API 似乎不允许这样做。 ContentProvider的openFile()返回一个ParcelFileDescriptor,从中可以得到一个java.io.FileDescriptor。然后,您可以使用此FileDescriptor 打开FileInputStreamFileOutputStream。不幸的是,您不能使用它来打开RandomAccessFile(尽管RandomAccessFile 在描述符上的工作方式与其他描述符相同,但API 中缺少您需要的构造函数)。

由于APK文件是ZIP文件,必须乱序读取(你必须寻找到最后找到文件目录),我假设安装的执行需要RandomAccessFile,所以它不会有能够支持您尝试实施的案例。

【讨论】:

  • 我同意您的评估,但尽管您的分析与我的分析不同,但它仍然与我差不多——“嗯,它不看起来可能的”。我坚持一些更确定的东西。 :-) 不过,如果我没有得到更好的东西,我会接受你的回答。谢谢!
  • 处理安装的 PackageManagerService 会创建 APK 文件的副本,因此不需要原始 URI 来提供具有查找能力的流。
  • 我通过内容提供商阅读了 zip 的内部信息(我为我的一个项目下载了插件,它们由内容提供商提供的 zip 组成)。
  • 请注意,Android 7.0+ 现在支持 content Uri 值。
【解决方案3】:

我同意 Jules 的分析,我会添加具体的精确度:

PackageInstallerActivity 中,它被一个apk 上的ACTION_VIEW 调用,在onCreate() 方法中有这个:

315 String apkPath = mPackageURI.getPath();
316 File apkFile = new File(apkPath);

在此之前,来自PackageUtil的这个方法被调用:

73 public static  PackageParser.Package getPackageInfo(Uri packageURI) {
74     final String archiveFilePath = packageURI.getPath();
75     PackageParser packageParser = new PackageParser(archiveFilePath);
76     File sourceFile = new File(archiveFilePath);
77     DisplayMetrics metrics = new DisplayMetrics();
78     metrics.setToDefaults();
79     return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
80 }

所有这些都倾向于确认 PackageManager 确实只需要文件 Uris。

你的日志,Skipping dir:packageParser.parsePackage中找到,测试Uri中给出​​的路径是否为文件。

【讨论】:

    【解决方案4】:

    我在我的一个应用程序中有这个,它允许我访问本地存储(在你尝试之前可以选择用户偏好;))

    import java.io.*;
    import android.content.*;
    import android.database.*;
    import android.net.*;
    import android.os.*;
    import android.preference.PreferenceManager;
    import android.util.Log;
    
    public class LocalFileContentProvider extends ContentProvider {
       private static final String URI_PREFIX = "content://your.content.provider.as.per.manifest";
    
       public static String constructUri(String url) {
           Uri uri = Uri.parse(url);
           return uri.isAbsolute() ? url : URI_PREFIX + url;
       }
    
       @Override
       public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    
           SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
    
           boolean allowLocal = app_preferences.getBoolean("allowLocalFiles", false);
    
            if (allowLocal) {    
                try {
                    File file = new File(uri.getPath());
    
                    if (file.isDirectory())
                        return null;
    
                    ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
                    return parcel;
                } catch (Exception e) {
                    return null;
                }
            } else {
                return null;
            }
    
       }
    
       @Override
       public boolean onCreate() {
           return true;
       }
    
       @Override
       public int delete(Uri uri, String s, String[] as) {
           throw new UnsupportedOperationException("Not supported by this provider");
       }
    
       @Override
       public String getType(Uri uri) {
           throw new UnsupportedOperationException("Not supported by this provider");
       }
    
       @Override
       public Uri insert(Uri uri, ContentValues contentvalues) {
           throw new UnsupportedOperationException("Not supported by this provider");
       }
    
       @Override
       public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
           throw new UnsupportedOperationException("Not supported by this provider");
       }
    
       @Override
       public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
           throw new UnsupportedOperationException("Not supported by this provider");
       }
    
    }
    

    我的清单包含

    <provider android:name="it.automated.android.kiosk.se.LocalFileContentProvider"
          android:authorities="it.automated" />
    

    然后开始安装(或操作)

    Intent viewIntent = new Intent(Intent.ACTION_VIEW);
    viewIntent.setDataAndType(Uri.parse(url), mimeType);
    

    【讨论】:

    • 我会再试一次。您的代码与我开始使用的代码几乎相同,但结果失败,如问题本身所述。谢谢!
    • 问题不在于提供方,因此即使您使用 API 演示代码 (developer.android.com/resources/samples/ApiDemos/src/com/…),问题仍然存在。
    • 您可以使用 WebView 作为中介,效果很好。
    • 嗨@CommonsWare我是新来的,也是android的初学者,我只需要你对你的问题的一点帮助,你能告诉我一个详细的答复吗?我怎样才能安装另一个应用程序应用程序的帮助,例如将 .apk 存储到应用程序中等
    • 简而言之,我想将一个 apk 与另一个 apk 绑定来安装,可以吗?如果可能有最新版本,请告诉我它是怎么回事
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    相关资源
    最近更新 更多