0

I'm setting up Google's APEZProvider to read .PNGs (compressed) and .MP3s (not compressed) from an APK Expansion zip file. File retrieval works just fine if I avoid the URI, and stick to "getAPKExpansionZipFile()" But when I try to retrieve my files using the "content://" API, I am getting a null InputStream. (I need the URI to satisfy the APIs of media players.)

This is for an Android app targeting API 26. In the past I was able to get the content provider working. But I've broken something. I wonder if it might be an issue with module versions not being in sync.

I've tried following a breakpoint through the APEZProvider (a subclass of ContentProvider that Google provides for this case.) The app finds the provider O.K. without any logcat error. So I think my manifest settings are correct.

At first the APEZProvider seems to initialize O.K. It even finds the zip files and correctly populates the mAPKExpansionPack private variable. But somehow when it is time to return an InputStream (in the ContentProvider superclass), I get null.

In my repository:

// This works fine
fun makeSureWeCanReadFromPack() {
     val stream = 
mExpansionPack?.getInputStream("images/species_bubo_bubo.png")
     val bitmap = BitmapFactory.decodeStream(stream)
     if (bitmap == null) {
        // This doesn't happen
        throw DodgyFileException("Couldn't read test image")
     }
}

// This throws an error
fun makeSureContentProviderIsUpAndRunning() {
    val uri = Uri.parse("content://com.company.app.provider.ZipFileContentProvider/images/species_bubo_bubo.png")
    val stream = mContext.getContentResolver().openInputStream(uri)
    val bitmap = BitmapFactory.decodeStream(stream)
    if (bitmap == null) {
        // This happens
        throw DodgyFileException("Couldn't read from content provider")
    }
}

In my Android manifest:

<provider android:authorities="com.company.app.provider.ZipFileContentProvider"
android:name="com.company.app.provider.ZipFileContentProvider"
android:exported = "true"
android:multiprocess = "true"
android:enabled = "true"
>
</provider>

EDIT: Here's the content provider: https://pastebin.com/UjMjtYCD

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
John Gorenfeld
  • 2,015
  • 1
  • 18
  • 27

1 Answers1

0

Solution: I needed to change my ZIP file so that it was built with no compression, using

zip -Z store

A big clue was when I realized that Android could get an input stream from the compressed .PNG, but not asset file descriptor.

The documentation hints at this requirement but the truth is a bit elusive. I mistakenly interpretated its advice to mean that you only need to avoid compression when dealing with playback media with offsets and duration, like songs and movies. But it turns out that compression can interfere with retrieving graphics files, too.

John Gorenfeld
  • 2,015
  • 1
  • 18
  • 27
  • wow I would not have even thought you could directly open an input stream on the compressed files in the first place, interesting! glad you figured it out :) – johnheroy Jan 02 '19 at 21:16
  • Yeah, good point, maybe that shouldn't have been allowed in the first place! I wonder if my InputStream was receiving unusable data. I did manage to create Bitmaps from it though...:) – John Gorenfeld Jan 02 '19 at 23:21