3

My apk version code is version 3. with it I am using main expansion file which was loaded with apk version code 1 (file name is similar to main.1.ex.etc.eg.obb). The expansion file downloads fine on a device.

The expansion file has media file, so I using APEZProvider from the Google Zip Expansion Library to play it with VideoView.

Calling VideoView.start() causes an Nullpointer exception.

What I have found so far: In APEZProvider.initIfNecessary() returns Main expansion file version as 3 instead of 1. Thus trying to open ZipResourceFile (mAPKExtensionFile) returns null. APEZProvider.openAssetFile() causes NullPointerException as mAPKExtensionFile is null.

Relevant code from APEZProvider class in Google Zip Expansion Library:

  private boolean initIfNecessary() {
    if ( !mInit ) {
        Context ctx = getContext();
        PackageManager pm = ctx.getPackageManager();
        ProviderInfo pi = pm.resolveContentProvider(getAuthority(), PackageManager.GET_META_DATA);
        PackageInfo packInfo;
        try {
            packInfo = pm.getPackageInfo(ctx.getPackageName(), 0);
        } catch (NameNotFoundException e1) {
            e1.printStackTrace();
            return false;
        }
        int patchFileVersion;
        int mainFileVersion;
        int appVersionCode = packInfo.versionCode;
        if ( null != pi.metaData ) {
            mainFileVersion = pi.metaData.getInt("mainVersion", appVersionCode);
            patchFileVersion = pi.metaData.getInt("patchVersion", appVersionCode);          
        } else {
            mainFileVersion = patchFileVersion = appVersionCode;
        }
        try {
            mAPKExtensionFile = APKExpansionSupport.getAPKExpansionZipFile(ctx, mainFileVersion, patchFileVersion);
            return true;
        } catch (IOException e) {
            e.printStackTrace();                
        }
    }
    return false;       
}



@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
        throws FileNotFoundException {
    initIfNecessary();
    String path = uri.getEncodedPath();
    if ( path.startsWith("/") ) {
        path = path.substring(1);
    }
    return mAPKExtensionFile.getAssetFileDescriptor(path);      
}

I am not sure about this line of code in the above: ProviderInfo pi = pm.resolveContentProvider(getAuthority(), PackageManager.GET_META_DATA); Is this correct?

From Android reference for PackageManager.resolveContentProvider().

public abstract ProviderInfo resolveContentProvider (String name, int flags)

Since: API Level 1 Find a single content provider by its base path name. Parameters

name: The name of the provider to find.

flags: Additional option flags. Currently should always be 0.

Can someone confirm if i am doing something wrong or is it a bug.

Edit: everything works as expected when I upload my app for the first time - its only when I update the apk resulting in different version codes that this problem occurs.

Ragunath Jawahar
  • 19,513
  • 22
  • 110
  • 155
user1318455
  • 43
  • 1
  • 7

3 Answers3

14

The Zip file provider class contains metadata that you can place in your AndroidManifest.zip file if the version number of the APK Expansion File does not match the version number of your APK.

<provider android:name=".APEZProvider"
              android:authorities="my.application.authority"
              android:exported="false"
              android:multiprocess="true"
    >
   <meta-data android:name="mainVersion"
              android:value="1"></meta-data>
   <meta-data android:name="patchVersion"
              android:value="2"></meta-data>
</provider>
dagalpin
  • 1,297
  • 8
  • 8
  • 1
    Works! Thanks. Shouldn't this have been more clearly documented or did I miss something obvious? Also for pm.resolveContentProvider(), the documentation says flags should be zero but this is not so in APEZProvider Class. Any clarification on this? – user1318455 Jun 10 '12 at 11:30
  • @user1318455 i got error while set provider in manifest : java.lang.RuntimeException: Unable to get provider com.dabbel.zipfile.APEZProvider: java.lang.InstantiationException: java.lang.Class cannot be instantiated – Pranav May 17 '19 at 05:28
2

You have to create your own provider and declare it in your manifest

 <provider android:authorities="com.myCompany.myAppName.provider.ZipFileContentProvider" android:name=".ZipFileContentProvider"></provider>

Taken from:

Where is the SampleZipfileProvider class?

Community
  • 1
  • 1
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • My question is not the same as the linked one. The provider is already declared. Video works fine with VideoView.setVideoURI() as long as apk version code and expansion file version are same. It doesn't work if apk version code is different from expansion file version. – user1318455 Apr 22 '12 at 19:04
  • Because it shouldn't. Your version code needs to match the expansion file name. – Blundell Apr 22 '12 at 19:20
  • If you upload an updated apk, you can use an expansion file uploaded with an earlier apk. In this case the file expansion version is different from apk version code - and everything works except for this accessing video through URI. To me it looks more of an APEZProvider issue. – user1318455 Apr 22 '12 at 19:27
  • From what I read of the documentation they want the file name to match version code. So whenever I update my app I just update with a new patch file. In your first comment you say setVideoUri works but then in your next comment you say it doesn't work :-/ – Blundell Apr 22 '12 at 19:30
  • From the documentation: "One of the great benefits to using expansion files on Google Play is the ability to update your application without re-downloading all of the original assets." and then "Existing users receive only the updated APK and the new patch expansion file (retaining the previous main expansion file)." The main file version would remain the same. And as i said everything works as expected even with different version except for videoURI which fails as mentioned in the code above. (setVideoURI only works when version is same for both app and expansion file) – user1318455 Apr 22 '12 at 19:35
  • More from documentation: "If you update your application with a new APK or upload multiple APKs for the same application, you can select expansion files that you've uploaded for a previous APK. The expansion file's name does not change—it retains the version received by the APK to which the file was originally associated." – user1318455 Apr 22 '12 at 19:40
  • And you override getAuthority() correctly? as well as add the provider to the manifest? – Blundell Apr 22 '12 at 19:40
  • yes. As I said everything works as expected when I upload my app for the first time - its only when I update the apk resulting in different version codes that this problem occurs. – user1318455 Apr 22 '12 at 19:44
  • I'm asking so many questions because it's not in your question. – Blundell Apr 22 '12 at 19:45
0

As you well say, the expansion file version number can be different of the app version. So the question is, how do I know the expansion file version number?

Here's one of the multiple possible answers:

From the APK Expansion Files guide:

There are many ways you could determine the expansion file version number. One simple way is to save the version in a SharedPreferences file when the download begins, by querying the expansion file name with the APKExpansionPolicy class's getExpansionFileName(int index) method. You can then get the version code by reading the SharedPreferences file when you want to access the expansion file.

For more information about reading from the shared storage, see the Data Storage documentation.

jBilbo
  • 1,683
  • 13
  • 24