Can We Install an APK From a ContentProvider?

后端 未结 4 1057
忘了有多久
忘了有多久 2020-12-08 03:57

I am working on a library to allow apps to self-update, for those that are being distributed outside of the Android Market.

My original plan was to include code that

相关标签:
4条回答
  • 2020-12-08 04:28

    I agree with Jules analysis, and I would add concrete precisions :

    In PackageInstallerActivity, which is called by ACTION_VIEW on an apk, there is this in the onCreate() method:

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

    And before that, this method from PackageUtil is called:

    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 }
    

    All this tends to confirm that the PackageManager do expects only File Uris.

    The log you have, Skipping dir: is found in packageParser.parsePackage, which tests whether the path given in the Uri is a file or not.

    0 讨论(0)
  • 2020-12-08 04:39

    I have this in one of my applications which allows me access to local storage (user preference selectable before you have a go at me ;) )

    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");
       }
    
    }
    

    My manifest contains

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

    and then to start the install (or action)

    Intent viewIntent = new Intent(Intent.ACTION_VIEW);
    viewIntent.setDataAndType(Uri.parse(url), mimeType);
    
    0 讨论(0)
  • 2020-12-08 04:45

    The documentation for ACTION_INSTALL_PACKAGE is incorrect. It too will only accept files.

    My only suggestion would therefore be to create a copy of the file in the applications file area, make it world readable, and clean up any left-over files at a later date.

    Previous incorrect answer: In 4.0 and above there is a ACTION_INSTALL_PACKAGE which will accept a content:// URI (JavaDoc), but, prior to that, you're limited to installing via ACTION_VIEW which does assume the URI passed is a file:// URI.

    0 讨论(0)
  • 2020-12-08 04:55

    I would assume this is not possible, as the Java API doesn't seem to allow it. ContentProvider's openFile() returns a ParcelFileDescriptor, from which you can obtain a java.io.FileDescriptor. You can then use this FileDescriptor to open either a FileInputStream or a FileOutputStream. Unfortunately, you can't use it to open a RandomAccessFile (despite the fact that RandomAccessFile works on descriptors just the same as the others, the constructor you'd need is just missing from the API).

    As APK files are ZIP files, which must be read out of order (you have to seek to the end to find the file directory), I assume the implementation of installation will require a RandomAccessFile, so it would not have been possible to support the case you're trying to implement.

    0 讨论(0)
提交回复
热议问题