我的应用程序大小约为< 200 MB大小,包含带有.jpg图像文件的资源文件夹。
第1步:
提供Manifist权限
<!-- Required to access Google Play Licensing -->
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<!-- Required to download files from Google Play -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required to keep CPU alive while downloading files (NOT to keep screen awake) -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Required to poll the state of the network connection and respond to changes -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Required to check whether Wi-Fi is enabled -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- Required to read and write the expansion files on shared storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第2步:
我使用了依赖项而不是导入模块
build.gradle;
repositories {
maven { url 'https://dl.bintray.com/alexeydanilov/apk-expansion' }
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
// APK Expansion library
compile 'com.google.android.gms:play-services:7.5.0'
compile files('libs/commons-io-2.4.jar')
// try using library too
// compile project(':aPKExpansionZipLibrary')
// compile project(':applicationLicensing')
// compile project(':downloaderLibrary')
compile 'com.danikula.expansion:expansion:1.1@aar'
compile 'com.danikula.expansion:license:1.5@aar'
compile 'com.danikula.expansion:zip:1.1@aar'
}
第3步:
下载服务类
公共类ExampleDownloaderService扩展了DownloaderService {
来自开发者资料的// BASE64_PUBLIC_KEY public static final String BASE64_PUBLIC_KEY =&#34; .............. oAtvtNLZ / tNm3okOpR7GsT58dMBsc .............&#34;;
//我把它随机....我不清楚,直到现在为什么这么随机 public static final byte [] SALT = new byte [] {1,4,-1,-1,14,42,-79,-21,13,2,-8,-11,62,1,-10, -101,-19,41,-12,18};
@Override
public String getPublicKey() {
return BASE64_PUBLIC_KEY;
}
@Override
public byte[] getSALT() {
return SALT;
}
@Override
public String getAlarmReceiverClassName() {
return ExampleAlarmReceiver.class.getName();
}
}
第4步:
Alaram接收器类:
public class ExampleAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, ExampleDownloaderService.class);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
第5步:
我创建了两个辅助类
Uitilities
public class Utilities {
private static final String TAG = "Utilities";
// The shared path to all app expansion files
public final static String EXP_PATH = "/Android/obb/";
public final static String EXP_DATA_PATH = "/Android/data/";
public final static long EXP_FILE_SIZE = 211434558L; // 154577244L
public final static int MAIN_VERSION = 2; // 1
public final static int PATCH_VERSION = 0;
public static final String PREFS_NAME = "FishGuidePrefsFile";
public static InputStream getAssetsPathInputStream(Context context, String internalPath) throws IOException {
// Get a ZipResourceFile representing a merger of both the main and
// patch files
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, MAIN_VERSION, PATCH_VERSION);
internalPath = "assets/" + internalPath;
// Get an input stream for a known file inside the expansion file ZIPs
return getAssetInputStream(context, internalPath);
}
public static AssetFileDescriptor getAssetsFileDescriptor(Context context, String internalPath) throws IOException {
// Get a ZipResourceFile representing a merger of both the main and
// patch files
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, MAIN_VERSION, PATCH_VERSION);
internalPath = "assets/" + internalPath;
// Get an input stream for a known file inside the expansion file ZIPs
return expansionFile.getAssetFileDescriptor(internalPath);
}
public static ZipResourceFile getAssetsZipResourceFile(Context context)
throws IOException {
// Get a ZipResourceFile representing a merger of both the main and
// patch files
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, MAIN_VERSION, PATCH_VERSION);
return expansionFile;
}
public static String[] getAPKExpansionFiles(Context ctx) {
return getAPKExpansionFiles(ctx, MAIN_VERSION, PATCH_VERSION);
}
public static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) {
String packageName = ctx.getPackageName();
Vector<String> ret = new Vector<String>();
Log.w(TAG, "packageName: " + packageName);
Log.w(TAG, "Environment.getExternalStorageState(): " + Environment.getExternalStorageState());
Log.w(TAG, "Environment.getExternalStorageDirectory(): " + Environment.getExternalStorageDirectory());
Log.w(TAG, "ctx.getFilesDir(): " + ctx.getFilesDir());
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// Build the full path to the app's expansion files
File root = Environment.getExternalStorageDirectory();
File expPath = new File(root.toString() + EXP_PATH + packageName);
// Check that expansion file path exists
if (expPath.exists()) {
if (mainVersion > 0) {
String strMainPath = expPath + File.separator + "main."
+ mainVersion + "." + packageName + ".obb";
File main = new File(strMainPath);
if (main.isFile()) {
ret.add(strMainPath);
}
}
if (patchVersion > 0) {
String strPatchPath = expPath + File.separator + "patch."
+ mainVersion + "." + packageName + ".obb";
File main = new File(strPatchPath);
if (main.isFile()) {
ret.add(strPatchPath);
}
}
}
}
String[] retArray = new String[ret.size()];
ret.toArray(retArray);
return retArray;
}
public static void unzipExpansionFile(String expPath, File outputDir) {
ZipHelper zh = new ZipHelper();
zh.unzip(expPath, outputDir);
}
public static File getExternalDataPath(Context ctx) {
String packageName = ctx.getPackageName();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// Build the full path to the app's expansion files
File root = Environment.getExternalStorageDirectory();
File expDataPath = new File(root.toString() + EXP_DATA_PATH + packageName);
// Check that expansion file path exists
// if (!expDataPath.exists()) {
// expDataPath.mkdirs();
// }
Log.d(TAG, "External Data Path: " + expDataPath.toString());
return expDataPath;
}
return null;
}
public static String getFullExternalDataPath(Context ctx, String assetPath) {
File baseDir = getExternalDataPath(ctx);
if (!assetPath.startsWith("assets")) {
assetPath = "assets/" + assetPath;
}
return baseDir + File.separator + assetPath;
}
public static InputStream getAssetInputStream(Context ctx, String path) {
try {
if (!path.startsWith("assets")) {
path = "assets/" + path;
}
File baseDir = getExternalDataPath(ctx);
String assetFilePath = baseDir + File.separator + path;
File assetFile = new File(assetFilePath);
Log.d(TAG, "Loading AssetInputStream for: " + assetFilePath
+ " => Exists: " + assetFile.exists());
return new FileInputStream(assetFilePath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void cleanUpOldData(Context ctx) {
try {
String packageName = ctx.getPackageName();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// Build the full path to the app's expansion files
File root = Environment.getExternalStorageDirectory();
File expPath = new File(root.toString() + EXP_PATH + packageName);
File expDataPath = new File(root.toString() + EXP_DATA_PATH + packageName);
// clean up the expanded data under EXP_DATA_PATH
boolean isDeleted = deleteDirectory(expDataPath);
Log.d(TAG, "Expanded data path deleted: " + isDeleted);
// clean up the obb file under EXP_PATH
int currentMainVersion = MAIN_VERSION - 1;
int currentPatchVersion = PATCH_VERSION - 1;
// Check that expansion file path exists
if (expPath.exists()) {
if (currentMainVersion > 0) {
String strMainPath = expPath + File.separator + "main." + currentMainVersion + "." + packageName + ".obb";
File main = new File(strMainPath);
if (main.exists()) {
isDeleted = main.delete();
}
}
Log.d(TAG, "Main OBB file deleted: " + isDeleted);
if (currentPatchVersion > 0) {
String strPatchPath = expPath + File.separator + "patch." + currentPatchVersion + "." + packageName + ".obb";
File patch = new File(strPatchPath);
if (patch.exists()) {
isDeleted = patch.delete();
}
Log.d(TAG, "Patch OBB file deleted: " + isDeleted);
}
}
}
} catch (Exception e) {
Log.e(TAG, "Unable to clean up old app data");
}
}
public static boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
if (files == null) {
return true;
}
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return (path.delete());
}
// public static String getFullExternalDataPath(Context ctx, String
// assetPath) {
// return "file:///android_asset/" + assetPath;
// }
//
// public static InputStream getAssetInputStream(Context ctx, String path) {
// try {
// AssetManager mgr = ctx.getAssets();
// return mgr.open(path, AssetManager.ACCESS_BUFFER);
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// } catch (Exception e) {
// // TODO: handle exception
// }
// return null;
// }
}
和其他类ZipHelper
public class ZipHelper {
private static final String TAG = "CoralSea.ZipHelper";
boolean zipError=false;
public boolean isZipError() {
return zipError;
}
public void setZipError(boolean zipError) {
this.zipError = zipError;
}
public void unzip(String archive, File outputDir) {
try {
Log.d(TAG,"ZipHelper.unzip() - File: " + archive);
ZipFile zipfile = new ZipFile(archive);
for (Enumeration e = zipfile.entries(); e.hasMoreElements(); ) {
ZipEntry entry = (ZipEntry) e.nextElement();
unzipEntry(zipfile, entry, outputDir);
}
}
catch (Exception e) {
Log.e(TAG,"ZipHelper.unzip() - Error extracting file " + archive+": "+ e);
setZipError(true);
}
}
private 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 {
copy(inputStream, outputStream);
}
catch (Exception e) {
Log.e(TAG,"ZipHelper.unzipEntry() - Error: " + e);
setZipError(true);
}
finally {
outputStream.close();
inputStream.close();
}
}
private void createDirectory(File dir) {
Log.d(TAG,"ZipHelper.createDir() - Creating directory: "+dir.getName());
if (!dir.exists()){
if(!dir.mkdirs()) throw new RuntimeException("Can't create directory "+dir);
}
else Log.d(TAG,"ZipHelper.createDir() - Exists directory: "+dir.getName());
}
// Copies src file to dst file.
// If the dst file does not exist, it is created
private void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
copy(in, out);
}
// Copies src file to dst file.
// If the dst file does not exist, it is created
private void copy(InputStream in, OutputStream out) throws IOException {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
第6步:
Spalsh Screen工作
最后: 创建扩展文件的过程:
- 使用main.2.com.example
创建新文件夹并重命名- 将所有图像放在文件夹
中- 使用0压缩
压缩此文件夹- 新生成的文件为main.2.com.example.zip&amp;使用main.2.com.example.obb重命名
醇>
所以我的问题是:
1. 如何制作单独的扩展文件,因为我的apk大小远大于50MB但小于200MB?
a&gt;处理扩展文件zip和/需要哪些类 下载?
b&gt;他们应该在哪里被召唤?
3. 使用扩展文件时的内存优化因素是什么?
我已经检查了类似于我的其他问题,但没有一个能解决我的任何目的!