有這樣一種需求,從服務器或者某些地方獲取一些指令境蜕,我們?nèi)ヌ幚磉@些指令谊惭,比方說打開某個界面汽馋,瀏覽某些網(wǎng)頁,下載某個文件等圈盔。
本文主要以這個例子說明:我要從某個網(wǎng)站下載QQ APK安裝到手機豹芯,那么我下載的是XX應用市場,然后安裝市場完他會去下載我想要的QQ 安裝包驱敲。那么铁蹈,應用市場是怎么知道的呢?
下面癌佩,我們就引入指令處理框架:
上述問題木缝,我們只要從應用市場的APK包里面獲取相應的指令,使用我們指令處理框架進行處理就好了围辙。就是那么簡單我碟。
- 我們的指令存放在哪里?
首先我們知道APK安裝包就是一個壓縮文件姚建,(我們給APK的后綴改成rar就能進行解壓)那么我們可以對這個壓縮文件添加一些附加信息矫俺。這樣我們在下載apk的時候,就會把相應的指令添加在應用市場apk的壓縮包里面。 - 獲取并處理指令:
1厘托、首先我們得得到應用市場的apk路徑地址友雳。
public static String getMyAPkPath(Context context) {
if (context == null) {
return null;
}
String installAPKPath = "";
String packageName = context.getPackageName();
try {
installAPKPath = context.getPackageManager().getApplicationInfo(
packageName, PackageManager.GET_UNINSTALLED_PACKAGES).sourceDir;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return installAPKPath;
}
第二部我們從該壓縮包得到我們的額外信息:
public static String extractZipComment(String filename) {
String retStr = null;
try {
File file = new File(filename);
int fileLen = (int) file.length();
FileInputStream in = new FileInputStream(file);
/* The whole ZIP comment (including the magic byte sequence)
* MUST fit in the buffer* otherwise, the comment will not be recognized correctly** You can safely increase the buffer size if you like*/
byte[] buffer = new byte[Math.min(fileLen, 8192)];
int len;
in.skip(fileLen - buffer.length);
if ((len = in.read(buffer)) > 0) {
retStr = getZipCommentFromBuffer(buffer, len);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return retStr;
}
另一個方法
private static String getZipCommentFromBuffer(byte[] buffer, int len) {
byte[] magicDirEnd = {0x50, 0x4b, 0x05, 0x06};
int buffLen = Math.min(buffer.length, len);
//Check the buffer from the end
for (int i = buffLen - magicDirEnd.length - 22; i >= 0; i--) {
boolean isMagicStart = true;
for (int k = 0; k < magicDirEnd.length; k++) {
if (buffer[i + k] != magicDirEnd[k]) {
isMagicStart = false;
break;
}
}
if (isMagicStart) {
//Magic Start found!
int commentLen = buffer[i + 20] + buffer[i + 22] * 256;
int realLen = buffLen - i - 22;
log("ZIP comment found at buffer position " + (i + 22) + " with len=" + commentLen + ", good!");
if (commentLen != realLen) {
log("WARNING! ZIP comment size mismatch: directory says len is " +commentLen + ", but file ends after " + realLen + " bytes!");
}
String comment = new String(buffer, i + 22, Math.min(commentLen, realLen));
return comment.trim();
}
}
log("ERROR! ZIP comment NOT found!");
return null;
}
該方法是得到應用市場apk安裝包的額外信息,也就是原始指令集合铅匹。該例子是使用json數(shù)組實現(xiàn)指令集的押赊。
下面我們開始構(gòu)造指令集處理框架:
首先我們把處理指令的共有的方法抽象成一個接口,
public interface InstructionInterface {
List<String> getInstructionList(String data);
boolean doInstructionList(Context context, List<String> orders);
}
然后定義一個管理類
public class InstructionManager {
private static final String TAG = InstructionManager.class.getSimpleName();
public static InstructionZIPImpl getZIPImpl() {
return new InstructionZIPImpl();
}}
管理類我們能得到一個具體的實現(xiàn)類的對象包斑,同時如果有其他類型的處理方式也會得到具體的處理類的對象流礁,還可以進行優(yōu)化。
現(xiàn)在我們看看具體的實現(xiàn)類:
public final class InstructionZIPImpl implements InstructionInterface {
private static final String TAG = InstructionZIPImpl.class.getSimpleName();
public InstructionZIPImpl() {
}
public String getComment(Context context) {
if (context == null) {
return "";
}
String path = InstructionUtils.getMyAPkPath(context);
if (TextUtils.isEmpty(path)) {
return "";
}
return InstructionUtils.extractZipComment(path);
}
@Override
public List<String> getInstructionList(String comment) {
List<String> orderLists = new ArrayList<>();
if (!TextUtils.isEmpty(comment)) {
List<String> orders = JsonUtils.stringListFromJson(comment);
if (orders != null) {
orderLists.addAll(orders);
}
}
return orderLists;
}
@Override
public boolean doInstructionList(Context context, List<String> orders) {
boolean isSuccess = true;
if (context == null || orders == null || orders.size() <= 0) {
return false;
}
for (String order : orders) {
boolean handleAction = Launcher.handleUriAction(context, Uri.parse(order));
if (!handleAction) {
isSuccess = false;
}
}
return isSuccess;
}}
其中InstructionUtils就是包含我們開始定義的兩個方法罗丰。
JsonUtils.stringListFromJson()是gson的方法神帅,就是把string類型的json串實例化。
寫代碼的時候要注意程序的健壯性萌抵,避免輸入錯誤數(shù)據(jù)不會造成我們方法內(nèi)部崩潰找御。
我們把String類型命令集合轉(zhuǎn)成我們需要的Uri類型的指令,下面是使用方法
也就是Launcher的方法
public static boolean handleUriAction(Context context, Uri uri) {
if (uri == null)
return false;
String scheme = uri.getScheme();
if ("my_order".equals(scheme)) {
String action = uri.getAuthority();
if ("do_something".equals(action)) {
doMyOrder(context, uri.getQueryParameter("my_data"));
}
return true;
}
return false;}private static void doMyOrder(Context context, String json) {
if (TextUtils.isEmpty(json)) {
return;
}
// TODO: 22/11/2016 we can do something with 'json'
//使用json實例化绍填,或者把需要的數(shù)據(jù)傳遞進來霎桅。就可以進行命令處理。
}
使用Uri我們很容易得到我們需要的東西沐兰。
上述代碼我給一個使用例子哆档,是三個指令的集合,我們只要對json進行解析就可以了
String testString = "[\"my_order://do_something/?my_data=\",\"my_order://do_something/?\",\"my_order://do_something/?\"]";
同樣住闯,我們從任何地方獲取指令都可以進行處理,具體的實現(xiàn)就可以在doMyOrder進行編碼澳淑。
本人程序界菜鳥一門比原,如有問題或者建議還望能批評指出。由于本文是框架類型杠巡,故源碼沒貼出來量窘,不過文章寫的很詳細,所有的代碼都在里面了氢拥。