Read content from APK expansion file (from obb file)

23,707

Solution 1

i have googled and found that we shold have to make .zip with 0% (No compression) that is mention in http://developer.android.com/google/play/expansion-files.html

Tip: If you're packaging media files into a ZIP, you can use media playback calls on the files with offset and length controls (such as MediaPlayer.setDataSource() and SoundPool.load()) without the need to unpack your ZIP. In order for this to work, you must not perform additional compression on the media files when creating the ZIP packages. For example, when using the zip tool, you should use the -n option to specify the file suffixes that should not be compressed: zip -n .mp4;.ogg main_expansion media_files

OR How to make 0% compression zip using winrar?

enter image description here

here see the compression method

0% compression zip in mac

Create zip without compression on OS X from Terminal:
zip -r0 zipfilename.zip files-to-zip

so we should have to upload this zip in play store.

so you not need to use ZipHelper.java

just simply use

ZipResourceFile expansionFile=null;

            try {
                expansionFile = APKExpansionSupport.getAPKExpansionZipFile(getApplicationContext(),3,0);

                     AssetFileDescriptor fd = expansionFile.getAssetFileDescriptor("test.mp4");
                     MediaPlayer mPlayer = new MediaPlayer();
                     mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                     mPlayer.setDataSource(fd.getFileDescriptor(),fd.getStartOffset(),fd.getLength());
                     mPlayer.prepare();
                     mPlayer.start();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

Solution 2

I have solved using unzipping..

ZipHelper.java

public class ZipHelper {
static boolean zipError = false;

public static boolean isZipError() {
    return zipError;
}

public static void setZipError(boolean zipError) {
    ZipHelper.zipError = zipError;
}

public static void unzip(String archive, File outputDir) {
    try {
        Log.d("control", "ZipHelper.unzip() - File: " + archive);
        ZipFile zipfile = new ZipFile(archive);
        for (Enumeration<? extends ZipEntry> e = zipfile.entries(); e
                .hasMoreElements();) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            unzipEntry(zipfile, entry, outputDir);

        }
    } catch (Exception e) {
        Log.d("control", "ZipHelper.unzip() - Error extracting file "
                + archive + ": " + e);
        setZipError(true);
    }
}

private static void unzipEntry(ZipFile zipfile, ZipEntry entry,
        File outputDir) throws IOException {
    if (entry.isDirectory()) {
        createDirectory(new File(outputDir, entry.getName()));
        return;
    }

    File outputFile = new File(outputDir, entry.getName());
    if (!outputFile.getParentFile().exists()) {
        createDirectory(outputFile.getParentFile());
    }

    Log.d("control", "ZipHelper.unzipEntry() - Extracting: " + entry);
    BufferedInputStream inputStream = new BufferedInputStream(
            zipfile.getInputStream(entry));
    BufferedOutputStream outputStream = new BufferedOutputStream(
            new FileOutputStream(outputFile));

    try {
        IOUtils.copy(inputStream, outputStream);
    } catch (Exception e) {
        Log.d("control", "ZipHelper.unzipEntry() - Error: " + e);
        setZipError(true);
    } finally {
        outputStream.close();
        inputStream.close();
    }
}

private static void createDirectory(File dir) {
    Log.d("control",
            "ZipHelper.createDir() - Creating directory: " + dir.getName());
    if (!dir.exists()) {
        if (!dir.mkdirs())
            throw new RuntimeException("Can't create directory " + dir);
    } else
        Log.d("control",
                "ZipHelper.createDir() - Exists directory: "
                        + dir.getName());
}
}

Usage

try {
        ZipResourceFile expansionFile = APKExpansionSupport
                .getAPKExpansionZipFile(this, 3, 0);

        ZipEntryRO[] zip = expansionFile.getAllEntries();
        Log.e("", "zip[0].isUncompressed() : " + zip[0].isUncompressed());
        Log.e("",
                "mFile.getAbsolutePath() : "
                        + zip[0].mFile.getAbsolutePath());
        Log.e("", "mFileName : " + zip[0].mFileName);
        Log.e("", "mZipFileName : " + zip[0].mZipFileName);
        Log.e("", "mCompressedLength : " + zip[0].mCompressedLength);

        File file = new File(Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "");
        ZipHelper.unzip(zip[0].mZipFileName, file);

        if (file.exists()) {
            Log.e("", "unzipped : " + file.getAbsolutePath());
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

Solution 3

Are your files inside a folder in the zip file? I ask because I had the same problem and my solution was to include the folder name when getting the file descriptor.

For instance, my expansion file contained a single folder named "Videos". So to get a file descriptor I had to do this:

AssetFileDescriptor fd = expansionFile.getAssetFileDescriptor("Videos/" + videoName + ".mp4");
Share:
23,707
Bhavesh Hirpara
Author by

Bhavesh Hirpara

I possess a passion for pushing web and mobile technologies to the limits and I can work with team of talented engineers to design and build the next generation of mobile applications. You can see my CV.

Updated on June 24, 2020

Comments

  • Bhavesh Hirpara
    Bhavesh Hirpara about 4 years

    I have implemented APK expansion file download service and all from http://developer.android.com/google/play/expansion-files.html

    I can download APK expansion file and I can see that file using below code

    try {
            ZipResourceFile expansionFile = APKExpansionSupport
                    .getAPKExpansionZipFile(this, 3, 0);
    
            ZipEntryRO[] zip = expansionFile.getAllEntries();
            Log.e("", "" + zip[0].mFile.getAbsolutePath());
            Log.e("", "" + zip[0].mFileName);
            Log.e("", "" + zip[0].mZipFileName);
            Log.e("", "" + zip[0].mCompressedLength);
    
            AssetFileDescriptor fd = expansionFile
                    .getAssetFileDescriptor(zip[0].mFileName);
    
            if (fd != null && fd.getFileDescriptor() != null) {
                MediaPlayer mp = new MediaPlayer();
                mp.setDataSource(fd.getFileDescriptor());
                mp.start();
            } else {
                Log.e("", "fd or fd.getFileDescriptor() is null");
            }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    

    My obb is having file test.mp4 and my code Log.e("", "" + zip[0].mFileName); prints test.mp4.

    My fd is null. Why is it null? I am trying to resolve but failed to resolve.

    I just can not read any file inside obb file.

    Unanswered Accessing to files inside obb expansion file suggesting idea but it does not work for me.

    Steps to create APK expansion file tells unzip content from obb and then read it. Is it reliable and good?

    I need an opinion on best practice.

    Edit

    My log

    03-01 10:36:40.848: E/(27836): zip[0].isUncompressed() : false
    03-01 10:36:40.848: E/(27836): mFile.getAbsolutePath() : /storage/sdcard0/Android/obb/smart.trigger/main.3.smart.trigger.obb
    03-01 10:36:40.848: E/(27836): mFileName : test.mp4
    03-01 10:36:40.848: E/(27836): mZipFileName : /storage/sdcard0/Android/obb/smart.trigger/main.3.smart.trigger.obb
    03-01 10:36:40.848: E/(27836): mCompressedLength : 21657598