android-多渠道自動打包之一秒五包

現在的渠道越來越多了,然後在打包的這個問題上要暫用非常多的時間,所以我也總結出了一篇關於自動打包的博文http://blog.csdn.net/a641832648/article/details/52163493

但是,apktool並不是萬能的,有時候會遇到一些莫名其妙的錯誤,然後實在是沒有辦法了,趕緊再去搜一搜有沒有什麼比較吊的多渠道自動打包方式。一搜還真的有!是美團的一個多渠道自動打包方式。具體的地址我找不到在哪了。。

這種打包方式我暫且稱之爲一秒五包。。。

我們知道,apk解壓出來的話裏面會有一個META-INF文件夾

然後一秒五包的打包方式就是在這個文件夾裏面增加一個空的文件夾。(至於爲什麼要多渠道打包可以在META-INF中增加一個空的文件而不影響apk,或者這個打包原理的話可以看一下apk的編譯過程跟原理。)

當然了,在這個META-INF文件夾中創建一個空的文件夾後,肯定要獲取,這個空文件夾,然後根據文件夾的文件名來唯一標識一個渠道。如:

要獲取360的渠道。則在META-INF文件夾增加一個BOKE_360,或者可以唯一標識的一個空文件:


然後在java代碼中獲取META-INF文件夾的這個空文件的文件名名就ok啦!!

public static String getChannel(Activity activity)
	  {
	    if (channel != null) {
	      return channel;
	    }
	    String start_flag = "META-INF/BOKE_";
	    ApplicationInfo appinfo = activity.getApplicationInfo();
	    String sourceDir = appinfo.sourceDir;
	    ZipFile zipfile = null;
	    try {
	      zipfile = new ZipFile(sourceDir);
	      Enumeration entries = zipfile.entries();
	      while (entries.hasMoreElements()) {
	        ZipEntry entry = (ZipEntry)entries.nextElement();
	        String entryName = entry.getName();
	        if (entryName.contains("META-INF/BOKE_")) {		//獲取BOKE_XXX
	          channel = entryName.replace("META-INF/BOKE_", "");		//截取BOKE_從而獲取渠道Id
	          break;
	        }
	      }
	    } catch (IOException e) {
	      e.printStackTrace();
	    }
	    finally{
	      if (zipfile != null) {
	        try {
	          zipfile.close();
	        } catch (IOException e) {
	          e.printStackTrace();
	        }
	      }
	    }
	 
	    return channel;
	  }
然後在適當的時候調用這個代碼就可以獲取到渠道號了!

然後手動的話根本不可能。。要自動打包的話,首先我們知道了這個獲取的方式。,要實現自動打包的話無非就是解壓apk,然後獲取往apk的META-INF文件夾中添加空文件夾。知道了這個實現過程,就可以寫一個批處理的jar包來來實現多渠道打包。。

以下是我寫的一個jar包:

public class SplitFastApk {    
	ArrayList<String> channel = new ArrayList<String>();    //渠道號  
	String curPath;						//當前文件夾路徑    
	String apkPath;  					//apk路徑  
	String endApkName;					//打包後的apk名稱
	int startNumber;					//打包的起始編號
	private String papau = "papau_";	//命名

	public SplitFastApk(String apkName) {// 構造函數接受參數    
		this.curPath = new File("").getAbsolutePath();    
		this.apkPath = apkName;    //傳入apk名稱
	}    

	public void mySplit() {    
		getCannelFile();// 獲得自定義的渠道號    
		modifyXudao();// 解包 - 打包 - 簽名    
	}    

	/**  
	 * 獲得渠道號  
	 */    
	private void getCannelFile() {    
		File f = new File("channel.txt");// 讀取當前文件夾下的channel.txt    
		if (f.exists() && f.isFile()) {    
			BufferedReader br = null;    
			FileReader fr = null;    
			try {    
				fr = new FileReader(f);    
				br = new BufferedReader(fr);    
				String line = null;    
				while ((line = br.readLine()) != null) {    
					String[] array = line.split("-");// 這裏是Tab分割   
					int start = Integer.parseInt(array[0]);   
					int end = Integer.parseInt(array[1]);
					for (int i = start; i <= end; i++) {	//獲取渠道號
						channel.add(""+i);  
					}
					this.endApkName = array[2];		//apk名字
					this.startNumber = Integer.parseInt(array[3]);//包的起始編號
				}    
			} catch (Exception e) {    
				e.printStackTrace();    
			} finally {    
				try {    
					if (fr != null) {    
						fr.close();    
					}    
					if (br != null) {    
						br.close();    
					}    
				} catch (IOException e) {    
					e.printStackTrace();    
				}    
			}    
			System.out.println("==INFO 1.==獲取渠道成功,一共有" + channel.size()    
					+ "個渠道======");    
			System.out.println("==INFO 1.==獲取名稱成功" + this.endApkName    
					+ "個渠道======");    
			System.out.println("==INFO 1.==編號成功,編號起始爲" + this.startNumber    
					+ "======");    
		} else {    
			System.out.println("==ERROR==channel.txt文件不存在,請添加渠道文件======");    
			System.exit(0);
		}    
	}    

	/**  
	 * apktool解壓apk,替換渠道值  
	 *   
	 * @throws Exception  
	 */    
	private void modifyXudao() {    
		// 創建生成結果的目錄    
		File f = new File("apk");    
		if (!f.exists()) {    
			f.mkdir();    
		}  
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < channel.size(); i++) {    

					ZipFile targetApk = null;	//目標apk
					ZipOutputStream originalApk = null;//母包apk
					try {    
						String id = channel.get(i);    
						System.out.println("==INFO 2. == 正在生成包: " + id    
								+ " ======");    
						String originalStr = curPath+"/apk/"+ endApkName + "" + startNumber + ".apk"; 
						targetApk = new ZipFile(apkPath);
						originalApk = new ZipOutputStream(new FileOutputStream(originalStr));

						// first, copy contents from existing war
						Enumeration<? extends ZipEntry> entries = targetApk.getEntries();
						while (entries.hasMoreElements()) {
							ZipEntry e = entries.nextElement();
							originalApk.putNextEntry(e);
							if (!e.isDirectory()) {
								copy(targetApk.getInputStream(e), originalApk);
							}
							originalApk.closeEntry();
						}
						ZipEntry e = new ZipEntry("META-INF/"+papau+id);//寫入一個名爲papau_XXX的空文件
						originalApk.putNextEntry(e);
						originalApk.closeEntry();
						System.out.println("==INFO 3 == 正在生成包: " + id    
								+ "成功 ======");
					} catch (Exception error) {    
						error.printStackTrace();  
						System.out.println("打包錯誤");
					} finally {    
						try {
							targetApk.close();
							originalApk.close();
						} catch (IOException e) {
							e.printStackTrace();
							System.out.println("打包錯誤");
						}
					}  
					startNumber++;
				}    
				System.out.println("==INFO 5 == 完成 ======");  
			}
		}).start();  
	}    

	// 4MB buffer
	private static final byte[] BUFFER = new byte[4096 * 1024];
	/**
	 * copy input to output stream - available in several StreamUtils or Streams classes 
	 */    
	public static void copy(InputStream input, OutputStream output) throws IOException {
		int bytesRead;
		while ((bytesRead = input.read(BUFFER))!= -1) {
			output.write(BUFFER, 0, bytesRead);
		}
	}
} 

我前面放的那個博文跟這個有點像,就是方式改了一下

ps:要把很多個jar包打包成一個jar包的話可以先把jar包解壓成class文件,然後cmd命令行進入目錄輸入jar cvf XXXX.jar *就會融合所有的jar包

發佈了34 篇原創文章 · 獲贊 30 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章