简体   繁体   中英

Read content from APK expansion file (from obb file)

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

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?

在此输入图像描述

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

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

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

If you use setDataSource() you are not supposed to compress your files when zipping them in the first place as it says in the docs ( http://developer.android.com/google/play/expansion-files.html#ZipLib ):

In order for this to work, you must not perform additional compression on the media files when creating the ZIP packages.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM