Android 热修复框架 Tinker ( 三 )
来源:互联网 发布:淘宝店铺四个钻石 编辑:程序博客网 时间:2024/05/18 19:47
这篇博客是基于Android 热修复框架 Tinker ( 一)写的,在看这篇博客之前请先看Android 热修复框架 Tinker ( 一 )。
1.方法替换
注意:下面是居于上一篇文章的项目(已经集成Tinker)
1.编写avtivity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="xmg.com.tinkertest.MainActivity"> <Button android:id="@+id/btn_mothed" android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="5dp" android:textAllCaps="false" /></RelativeLayout>
2.编写MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //补丁所在的路劲 String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; //添加补丁 TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //1.演示方法的替换: final Button mButton=(Button)findViewById(R.id.btn_mothed); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String name = getName(); mButton.setText(name); } }); } private String getName() { return "登录"; }}
3.修改app/build.gradle:
tinkerBuildFlavorDirectory
注释掉,因为暂时不用到多渠道打包。
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //for normal build //old apk file to build patch apk tinkerOldApkPath = "${bakPath}/app-debug-1218-16-32-05.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-1218-16-32-05-R.txt" //only use for build all flavor, if not, just ignore this field// tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"}
4.开始打包:
点击assembleRelease后,在app/build/apk下生成:下面三个文件
5.将apk安装在模拟器中
安装:app-release-1220-10-49-26.apk
当点击button的时候出现:登录
6.修改代码,:
替换掉MainActivity中的getName() 方法
public class MainActivity extends AppCompatActivity { private TextView tv_show; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //1.演示方法的替换: final Button mButton=(Button)findViewById(R.id.btn_mothed); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {// String name = getName(); // 该方法被下面的方法替换 String name=getNameFromValuse(); mButton.setText(name); } }); } private String getName() { return "登录"; } /** * 从资源文件上获取文字 * @return */ private String getNameFromValuse(){ String name=getResources().getString(R.string.mothed_name); return name; }}
在vaulse包下的strings.xml中添加:
<string name="mothed_name">替换了getName的方法</string>
7.修改build.gradle的配置文件
启用并修改下面两个属性,并启用它们在该gradle被引用的地方,因为在第一打包的时候已把它们注释了
tinkerOldApkPath = "${bakPath}/app-release-1220-10-49-26.apk" //上面打包生成的.apktinkerApplyMappingPath = "${bakPath}/app-release-1220-10-49-26-mapping.txt"//上面生成的mapping.txttinkerApplyResourcePath = "${bakPath}/app-release-1220-10-49-26-R.txt" //上面打包生成的R.txt
8.一件制作补丁包:
调用tinkerPatchRelease
, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/
。
9.打补丁:
然后我们将patch_signed_7zip.apk
补丁包 推送到手机的sdcard中
10.重新启动APP( 有时需要重新启动APP才能生效 )
再次点击chick me的时候就会冒出Toast:
现在我们就可以实现在没有重新安装apk的前提下动态发布代码,动态添加代码修复bugs。
11.总结:
1.Tinker可以实现方法的替换
2.Tinker可以实现对res资源下的valuse文件夹下的资源操作
2.类替换
1.编写avtivity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="xmg.com.tinkertest.MainActivity"> <Button android:id="@+id/btn_class" android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="5dp" android:text="AUtils.Class" android:textAllCaps="false" /></RelativeLayout>
2.编写MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //补丁所在的路劲 String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; //添加补丁 TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //2.演示类的替换 final Button btn_class = (Button) findViewById(R.id.btn_class); btn_class.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //新建了一个A类的对象 A a = new A(); btn_class.setText(a.getName()); } }); }}
3.新添加一个A.java类
public class A { public String getName(){ return "Name is form A Class "; }}
4.修改app/build.gradle:
tinkerBuildFlavorDirectory
注释掉,因为暂时不用到多渠道打包。
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //for normal build //old apk file to build patch apk tinkerOldApkPath = "${bakPath}/app-debug-1218-16-32-05.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-1218-16-32-05-R.txt" //only use for build all flavor, if not, just ignore this field// tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"}
5.开始打包:
点击assembleRelease后,在app/build/apk下生成:下面三个文件
6.将apk安装在模拟器中
安装:app-release-1220-10-49-26.apk
当点击button的时候出现:Name is form A Class
7.修改代码,:
添加一个B.java类
public class B { public String getName(Context context){ try { InputStream in = context.getAssets().open("config.txt"); BufferedReader reader=new BufferedReader(new InputStreamReader(in)); String s = reader.readLine(); return s; } catch (IOException e) { e.printStackTrace(); } return " IOException is from B class"; }}
在Assets文件夹中添加config.txt文件, 并输入
Name if from B Class
在MainActivity中用B类替换A类
public class MainActivity extends AppCompatActivity { private TextView tv_show; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //2.演示类的替换 final Button btn_class = (Button) findViewById(R.id.btn_class); btn_class.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {// A a = new A();// btn_class.setText(a.getName()); //B类替换了A类 B b=new B(); String name = b.getName(MainActivity.this); btn_class.setText(name); } }); }}
8.修改build.gradle的配置文件
启用并修改下面两个属性,并启用它们在该gradle被引用的地方,因为在第一打包的时候已把它们注释了
tinkerOldApkPath = "${bakPath}/app-release-1220-10-49-26.apk" //上面打包生成的.apktinkerApplyMappingPath = "${bakPath}/app-release-1220-10-49-26-mapping.txt"//上面生成的mapping.txttinkerApplyResourcePath = "${bakPath}/app-release-1220-10-49-26-R.txt" //上面打包生成的R.txt
9.一件制作补丁包:
调用tinkerPatchRelease
, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/
。
10.打补丁:
然后我们将patch_signed_7zip.apk
补丁包 推送到手机的sdcard中
11.重新启动APP( 有时需要重新启动APP才能生效 )
再次点击button的时候就会冒出:name if from B Class
现在我们就可以实现在没有重新安装apk的前提下动态发布代码,动态添加代码修复bugs。
12.总结:
1.Tinker可以实现添加类,并实现类的替换
2.Tinker可以实现对Assets资源下的文件进行操作
3.资源替换
1.编写avtivity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="xmg.com.tinkertest.MainActivity"> <ImageView android:layout_width="90dp" android:layout_height="90dp" android:src="@mipmap/ic_launcher" android:layout_gravity="center" android:layout_marginTop="10dp" /> <EditText android:layout_width="match_parent" android:layout_height="60dp" android:layout_margin="5dp" android:hint="输入账号" android:paddingLeft="10dp" /> <EditText android:layout_width="match_parent" android:layout_height="60dp" android:layout_margin="5dp" android:hint="输入密码" android:paddingLeft="10dp" /> <Button android:layout_width="match_parent" android:layout_height="60dp" android:layout_margin="5dp" android:text="登录" /> <Button android:id="@+id/btn_Theme" android:layout_width="match_parent" android:layout_height="60dp" android:layout_margin="5dp" android:text="切换主题" /></RelativeLayout>
2.编写MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //补丁所在的路劲 String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; //添加补丁 TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //3.演示资源的替换 final Button btn_class =(Button)findViewById(R.id.btn_Theme); btn_class.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "资源替换", Toast.LENGTH_SHORT).show(); } }); }}
3.修改app/build.gradle:
tinkerBuildFlavorDirectory
注释掉,因为暂时不用到多渠道打包。
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //for normal build //old apk file to build patch apk tinkerOldApkPath = "${bakPath}/app-debug-1218-16-32-05.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-1218-16-32-05-R.txt" //only use for build all flavor, if not, just ignore this field// tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"}
4.开始打包:
点击assembleRelease后,在app/build/apk下生成:下面三个文件
5.将apk安装在模拟器中
安装:app-release-1220-10-49-26.apk
当点击切换主题的时候出现:资源替换
6.修改代码,:
修改MainActivity.java
public class MainActivity extends AppCompatActivity { private TextView tv_show; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //切换主题 sp= getSharedPreferences("config", 0); boolean theme = sp.getBoolean("theme",true); if(theme){ this.setTheme(R.style.DayTheme); }else{ this.setTheme(R.style.NightTheme); } setContentView(R.layout.activity_main); String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //3.演示资源的替换:切换主题 final Button btn_class =(Button)findViewById(R.id.btn_Theme); btn_class.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {// Toast.makeText(MainActivity.this, "资源替换", Toast.LENGTH_SHORT).show(); boolean theme = sp.getBoolean("theme",true); sp.edit().putBoolean("theme",!theme).commit(); MainActivity.this.recreate();//从新Create Activity } }); }}
在vaulse包下的styles.xml中添加:
<!--白天主题--> <style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">#03A9F4</item> <item name="android:textColorPrimary">#ffffff</item> <item name="android:windowBackground">@color/background_material_light</item> <item name="colorAccent">#00BCD4</item> <item name="colorControlNormal">#00BCD4</item> <item name="android:textColor">#9C27B0</item> <item name="android:textSize">16sp</item> </style> <!--夜晚主题--> <style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">#00796B</item> <item name="android:textColorPrimary">#212121</item> <item name="android:windowBackground">@color/background_material_dark</item> <item name="colorAccent">#00796B</item> <item name="colorControlNormal">#212121</item> <item name="android:textColor">#212121</item> <item name="android:textSize">20sp</item> </style>
7.修改build.gradle的配置文件
启用并修改下面两个属性,并启用它们在该gradle被引用的地方,因为在第一打包的时候已把它们注释了
tinkerOldApkPath = "${bakPath}/app-release-1220-10-49-26.apk" //上面打包生成的.apktinkerApplyMappingPath = "${bakPath}/app-release-1220-10-49-26-mapping.txt"//上面生成的mapping.txttinkerApplyResourcePath = "${bakPath}/app-release-1220-10-49-26-R.txt" //上面打包生成的R.txt
8.一件制作补丁包:
调用tinkerPatchRelease
, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/
。
9.打补丁:
然后我们将patch_signed_7zip.apk
补丁包 推送到手机的sdcard中
10.重新启动APP( 有时需要重新启动APP才能生效 )
再次点击切换主题的时候就会:切换主题
现在我们就可以实现在没有重新安装apk的前提下动态发布代码,动态添加代码修复bugs。
11.总结:
1.Tinker可以实现资源的替换
2.Tinker可以实现对res资源下的valuse文件夹下的资源操作
4.So替换
1.编写avtivity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="xmg.com.tinkertest.MainActivity"> <Button android:id="@+id/btn_so" android:layout_width="match_parent" android:layout_height="60dp" android:layout_margin="5dp" android:text="So的替换" android:textAllCaps="false" /></RelativeLayout>
2.编写MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String path= Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"; TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path ); Log.d("TAG","path="+path); //4.演示So的替换 final Button btn_so=(Button)findViewById(R.id.btn_so); btn_so.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //for lib/armeabi, just use TinkerInstaller.loadLibrary TinkerInstaller.loadArmLibrary(this,"testShare");//加载testShare.so String version1 =TestShare.getVersionStatic1(); Log.d("TAG","version1="+version1); btn_so.setText(version1); } }); }}
3.添加testShare.so库
4.添加TestShare.java
新建一个包:xmg.com.ndktest.ndk
然后把TestShare.java 类添加到该包中
public class TestShare { static { System.loadLibrary("testShare"); } public native String getVersion1(); public static native String getVersionStatic1();}
5.修改app/build.gradle:
tinkerBuildFlavorDirectory
也注释掉,因为暂时不用到多渠道打包。
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //for normal build //old apk file to build patch apk tinkerOldApkPath = "${bakPath}/app-debug-1218-16-32-05.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-1218-16-32-05-R.txt" //only use for build all flavor, if not, just ignore this field tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"}
6.开始打包:
点击assembleRelease后,在app/build/apk下生成:下面三个文件
7.将apk安装在模拟器中
安装:app-release-1220-10-49-26.apk
当点击button的时候出现:Hello World from jni 1.0.0!
8.修改代码,:
修改MainActivity中的代码
public class MainActivity extends AppCompatActivity { private TextView tv_show; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //4.演示So的替换 //for lib/armeabi, just use TinkerInstaller.loadLibrary TinkerInstaller.loadArmLibrary(this,"testShare");//加载testShare final Button btn_so=(Button)findViewById(R.id.btn_so); btn_so.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //替换换成so的第二版本库 String version2 =TestShare.getVersionStatic2(); Log.d("TAG","version2="+version2); btn_so.setText(version2); } }); }}
修改TestShare.java
public class TestShare { static { System.loadLibrary("testShare"); } public native String getVersion1(); public static native String getVersionStatic1(); //添加下面两个本地方法 public native String getVersion2(); public static native String getVersionStatic2();}
把lib下所有的so库全部替换成第二版本的so库:
9.修改build.gradle的配置文件
启用并修改下面两个属性,并启用它们在该gradle被引用的地方,因为在第一打包的时候已把它们注释了
tinkerOldApkPath = "${bakPath}/app-release-1220-10-49-26.apk" //上面打包生成的.apktinkerApplyMappingPath = "${bakPath}/app-release-1220-10-49-26-mapping.txt"//上面生成的mapping.txttinkerApplyResourcePath = "${bakPath}/app-release-1220-10-49-26-R.txt" //上面打包生成的R.txt
8.一件制作补丁包:
调用tinkerPatchRelease
, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/
。
9.打补丁:
然后我们将patch_signed_7zip.apk
补丁包 推送到手机的sdcard中
10.重新启动APP( 有时需要重新启动APP才能生效 )
再次点击chick me的时候就会冒出Toast:
现在我们就可以实现在没有重新安装apk的前提下动态发布代码,动态更新so库。
11.总结:
1.Tinker可以实现so库动态的更新
该项目下载地址
- Android 热修复框架 Tinker ( 三 )
- Android 热修复框架 Tinker ( 一 )
- Android 热修复框架 Tinker ( 二 )
- android热修复框架Tinker(一)
- Android热修复框架 Tinker 接入
- Android热修复框架Tinker初体验
- Android热修复 Tinker
- Android热修复Tinker
- android 热修复 Tinker
- Android Tinker热修复
- Android热修复学习(三)微信热修复 tinker
- 接入热修复框架TinKer
- Android热修复之Tinker
- Android 热修复 Tinker接入
- Android 热修复 Tinker 接入
- Android 笔记: Tinker 热修复框架 简单上手教程
- [Android]腾讯Tinker热修复框架简单使用
- Android 热修复方案Tinker(三) Dex补丁加载
- Linux下的Memcache安装及安装Memcache的PHP扩展安装
- 数据中心网络里的Underlay和Overlay
- VisualVM远程连接并监控服务器上的jvm进程
- iOS程序设计心得总结(二)网络层设计
- iOS build 与version,InfoDictionary version的区别
- Android 热修复框架 Tinker ( 三 )
- easyUI的不同部门查看不同的信息sql语句和总结
- Jsp内置对象
- Linux系统中各种系统日志文件主要存放在系统中哪个目录
- java的switch语句问题
- redis高可用集群介绍
- 一键打包出多个不同包名,不同应用名称和图标的APK
- Java六大设计原则-单一原则
- caffe增加自己的layer实战(下-续1)--caffe学习(13)