dependencies {
compile 'com.alipay.euler:andfix:0.3.1@aar'
}
或者
使用module的方式添加andfix,这样可以直接查看编辑源码。记得新建jniLibs文件夹,将AndFix里面的libs里的so文件移到jniLibs里。
patchManager = new PatchManager(context);
patchManager.init(appversion);//current version
patchManager.loadPatch();
patchManager.addPatch(path);//path是补丁的存放路径
com.alipay.euler.andfix.AndFix
com.alipay.euler.andfix.annotation.MethodReplace
-keep class * extends java.lang.annotation.Annotation-keepclasseswithmembernames class * { native <methods>;}
项目中提供了一个生成补丁(后缀为 .apatch )的工具 apkpatch
usage: apkpatch
-f <new> -t <old> -o <output> -k <keystore> -p <***> 秘钥密码 -a <alias> -e <***> 别名密码
-a,--alias <alias> keystore entry alias. -e,--epassword <***> keystore entry password. -f,--from <loc> new Apk file path. -k,--keystore <loc> keystore path. -n,--name <name> patch name. -o,--out <dir> output dir. -p,--kpassword <***> keystore password. -t,--to <loc> old Apk file path.
例如:
./apkpatch.sh -f /Users/e0uoq/AndfixDemo2/app-release.apk -t /Users/e0uoq/AndfixDemo2/app/app-release.apk -o /Users/e0uoq/andfixpatch -k /Users/e0uoq/andfixkey.jks -p andfix_key -a andfixsign -e andfix_sign
usage: apkpatch
-m <apatch_path...> -o <output> -k <keystore> -p <***> -a <alias> -e <***> -a,--alias <alias> keystore entry alias. -e,--epassword <***> keystore entry password. -k,--keystore <loc> keystore path. -m,--merge <loc...> path of .apatch files. -n,--name <name> patch name. -o,--out <dir> output dir. -p,--kpassword <***> keystore password.
前提是环境基本已经配好
相关资料工具及demo下载地址:http://pan.baidu.com/s/1hsdcs7a
package com.example.lhx.andfixdemo;
import android.app.Application;
import android.os.Environment;
import android.util.Log;
import com.alipay.euler.andfix.patch.PatchManager;
import java.io.File;
import java.io.IOException;
/** * sample application * */
public class MainApplication extends Application {
private static final String TAG = " andrew";
private static final String APATCH_PATH = "/out.apatch";
private static final String DIR = "apatch";//补丁文件夹
/** * patch manager */
private PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
// initialize
mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
Log.d(TAG, "inited.");
// load patch
mPatchManager.loadPatch();
try {
// .apatch file path
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);
Log.d(TAG, "apatch:" + patchFileString + " added.");
//复制且加载补丁成功后,删除下载的补丁
File f = new File(this.getFilesDir(), DIR + APATCH_PATH);
if (f.exists()) {
boolean result = new File(patchFileString).delete();
if (!result)
Log.e(TAG, patchFileString + " delete fail");
}
} catch (IOException e) {
Log.e(TAG, "", e);
}
}
}
demo的场景就是一开始点击确定按钮textview显示I am old.然后假设这个方法有问题,我改为I am new.区分新包和旧包。
打包1.apk后,修改textviewt内容,打包2.apk
package com.example.lhx.andfixdemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/** * main activity */
public class MainActivity extends Activity {
private TextView mShowTextView;
private Button mSureButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mShowTextView = (TextView) this.findViewById(R.id.show_tv);
mSureButton = (Button) this.findViewById(R.id.sure_btn);
//打包1.apk后,修改textviewt内容,打包2.apk
mSureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mShowTextView.setText("I am new");
}
});
}
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\android_sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-optimizationpasses 5 # 指定代码的压缩级别 -dontusemixedcaseclassnames # 是否使用大小写混合 -dontskipnonpubliclibraryclasses # 是否混淆第三方jar -dontpreverify # 混淆时是否做预校验 -verbose # 混淆时是否记录日志 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
#重要,別忘了這些,不混淆andfix包,不混淆native方法
-dontwarn android.annotation -dontwarn com.alipay.euler.** -keep class com.alipay.euler.** {*;} -keep class * extends java.lang.annotation.Annotation -keepclasseswithmembernames class * { native <methods>;
}<span style="font-size:18px;"></span>