美文网首页
Robust热更应用在APP项目

Robust热更应用在APP项目

作者: 哈哈V青春 | 来源:发表于2018-03-12 15:19 被阅读0次

    由于项目中需要使用到美团的robust热更方案,所以写篇文章来记录一下使用步骤,以防忘记。官方提供的教程是将robust应用到APP项目中,我就先从app入手。
    1、先在AS上面新建一个HotDemo APP,在App的build.gradle,加入如下依赖

    //制作补丁时将这个打开,auto-patch-plugin紧跟着com.android.application
    //apply plugin: 'auto-patch-plugin'
    apply plugin: 'robust'
    
    compile 'com.meituan.robust:robust:0.4.78'
    

    2、在整个项目的build.gradle加入classpath

    classpath 'com.meituan.robust:gradle-plugin:0.4.78'
    classpath 'com.meituan.robust:auto-patch-plugin:0.4.78'
    

    3、新建文件名为robust.xml(文件名不能修改)的文件,文件路径在app项目的根目录下,并将如下配置拷贝到文件中。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <switch>
            <!--true代表打开Robust,请注意即使这个值为true,Robust也默认只在Release模式下开启-->
            <!--false代表关闭Robust,无论是Debug还是Release模式都不会运行robust-->
            <turnOnRobust>true</turnOnRobust>
            <!--<turnOnRobust>false</turnOnRobust>-->
    
            <!--是否开启手动模式,手动模式会去寻找配置项patchPackname包名下的所有类,自动的处理混淆,然后把patchPackname包名下的所有类制作成补丁-->
            <!--这个开关只是把配置项patchPackname包名下的所有类制作成补丁,适用于特殊情况,一般不会遇到-->
            <!--<manual>true</manual>-->
            <manual>false</manual>
    
            <!--是否强制插入插入代码,Robust默认在debug模式下是关闭的,开启这个选项为true会在debug下插入代码-->
            <!--但是当配置项turnOnRobust是false时,这个配置项不会生效-->
            <!--<forceInsert>true</forceInsert>-->
            <forceInsert>false</forceInsert>
    
            <!--是否捕获补丁中所有异常,建议上线的时候这个开关的值为true,测试的时候为false-->
            <catchReflectException>true</catchReflectException>
            <!--<catchReflectException>false</catchReflectException>-->
    
            <!--是否在补丁加上log,建议上线的时候这个开关的值为false,测试的时候为true-->
            <!--<patchLog>true</patchLog>-->
            <patchLog>false</patchLog>
    
            <!--项目是否支持progaurd-->
            <proguard>false</proguard>
            <!--<proguard>false</proguard>-->
    
            <!--项目是否支持ASM进行插桩,默认使用ASM,推荐使用ASM,Javaassist在容易和其他字节码工具相互干扰-->
            <useAsm>true</useAsm>
            <!--<useAsm>false</useAsm>-->
        </switch>
    
        <!--需要热补的包名或者类名,这些包名下的所有类都被会插入代码-->
        <!--这个配置项是各个APP需要自行配置,就是你们App里面你们自己代码的包名,
        这些包名下的类会被Robust插入代码,没有被Robust插入代码的类Robust是无法修复的-->
        <packname name="hotfixPackage">
            <name>com.xy.demo</name>
        </packname>
    
        <!--不需要Robust插入代码的包名,Robust库不需要插入代码,如下的配置项请保留,还可以根据各个APP的情况执行添加-->
        <exceptPackname name="exceptPackage">
            <name>com.meituan.robust</name>
            <name>com.meituan.sample.extension</name>
        </exceptPackname>
    
        <!--补丁的包名,请保持和类PatchManipulateImp中fetchPatchList方法中设置的补丁类名保持一致( setPatchesInfoImplClassFullName("com.meituan.robust.patch.PatchesInfoImpl")),
        各个App可以独立定制,需要确保的是setPatchesInfoImplClassFullName设置的包名是如下的配置项,类名必须是:PatchesInfoImpl-->
        <patchPackname name="patchPackname">
            <name>com.xy.demo</name>
        </patchPackname>
    
        <!--自动化补丁中,不需要反射处理的类,这个配置项慎重选择-->
        <noNeedReflectClass name="classes no need to reflect">
    
        </noNeedReflectClass>
    </resources>
    
    

    4、经robust.xml如下配置改为自己项目中需要插入代码的包名

    <!--需要热补的包名或者类名,这些包名下的所有类都被会插入代码-->
        <!--这个配置项是各个APP需要自行配置,就是你们App里面你们自己代码的包名,
        这些包名下的类会被Robust插入代码,没有被Robust插入代码的类Robust是无法修复的-->
        <packname name="hotfixPackage">
            <name>com.xy.demo</name>
        </packname>
    

    5、新建类PatchManipulateImp,代码中都有详细注释,如下

    package com.xy.demo;
    
    import android.content.Context;
    import android.os.Environment;
    import android.util.Log;
    
    import com.meituan.robust.Patch;
    import com.meituan.robust.PatchManipulate;
    import com.meituan.robust.RobustApkHashUtils;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by mivanzhang on 17/2/27.
     *
     * We recommend you rewrite your own PatchManipulate class ,adding your special patch Strategy,in the demo we just load the patch directly
     *
     * <br>
     *   Pay attention to the difference of patch's LocalPath and patch's TempPath
     *
     *     <br>
     *    We recommend LocalPath store the origin patch.jar which may be encrypted,while TempPath is the true runnable jar
     *<br>
     *<br>
     *    我们推荐继承PatchManipulate实现你们App独特的A补丁加载策略,其中setLocalPath设置补丁的原始路径,这个路径存储的补丁是加密过得,setTempPath存储解密之后的补丁,是可以执行的jar文件
     *     <br>
     *     setTempPath设置的补丁加载完毕即刻删除,如果不需要加密和解密补丁,两者没有啥区别
     */
    
    public class PatchManipulateImp extends PatchManipulate {
        /***
         * connect to the network ,get the latest patches
         * l联网获取最新的补丁
         * @param context
         *
         * @return
         */
        @Override
        protected List<Patch> fetchPatchList(Context context) {
            //将app自己的robustApkHash上报给服务端,服务端根据robustApkHash来区分每一次apk build来给app下发补丁
            //apkhash is the unique identifier for  apk,so you cannnot patch wrong apk.
            String robustApkHash = RobustApkHashUtils.readRobustApkHash(context);
            Log.w("robust","robustApkHash :" + robustApkHash);
            //connect to network to get patch list on servers
            //在这里去联网获取补丁列表
            Patch patch = new Patch();
            patch.setName("123");
            //we recommend LocalPath store the origin patch.jar which may be encrypted,while TempPath is the true runnable jar
            //LocalPath是存储原始的补丁文件,这个文件应该是加密过的,TempPath是加密之后的,TempPath下的补丁加载完毕就删除,保证安全性
            //这里面需要设置一些补丁的信息,主要是联网的获取的补丁信息。重要的如MD5,进行原始补丁文件的简单校验,以及补丁存储的位置,这边推荐把补丁的储存位置放置到应用的私有目录下,保证安全性
            patch.setLocalPath(Environment.getExternalStorageDirectory().getPath()+ File.separator+"robust"+ File.separator + "patch");
    
            //setPatchesInfoImplClassFullName 设置项各个App可以独立定制,需要确保的是setPatchesInfoImplClassFullName设置的包名是和xml配置项patchPackname保持一致,而且类名必须是:PatchesInfoImpl
            //请注意这里的设置
            patch.setPatchesInfoImplClassFullName("com.xy.demo.PatchesInfoImpl");
            List patches = new ArrayList<Patch>();
            patches.add(patch);
            return patches;
        }
    
        /**
         *
         * @param context
         * @param patch
         * @return
         *
         * you can verify your patches here
         */
        @Override
    
        protected boolean verifyPatch(Context context, Patch patch) {
            //do your verification, put the real patch to patch
            //放到app的私有目录
            patch.setTempPath(context.getCacheDir()+ File.separator+"robust"+ File.separator + "patch");
            //in the sample we just copy the file
            try {
                copy(patch.getLocalPath(), patch.getTempPath());
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("copy source patch to local patch error, no patch execute in path "+patch.getTempPath());
            }
    
            return true;
        }
        public void copy(String srcPath, String dstPath) throws IOException {
            File src=new File(srcPath);
            if(!src.exists()){
                throw new RuntimeException("source patch does not exist ");
            }
            File dst=new File(dstPath);
            if(!dst.getParentFile().exists()){
                dst.getParentFile().mkdirs();
            }
            InputStream in = new FileInputStream(src);
            try {
                OutputStream out = new FileOutputStream(dst);
                try {
                    // Transfer bytes from in to out
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }
                } finally {
                    out.close();
                }
            } finally {
                in.close();
            }
        }
        /**
         *
         * @param patch
         * @return
         *
         * you may download your patches here, you can check whether patch is in the phone
         */
        @Override
        protected boolean ensurePatchExist(Patch patch) {
            return true;
        }
    }
    
    

    6、初始化robust

    private void initRobust(){
            new PatchExecutor(this, new PatchManipulateImp(), new Callback()).start();
        }
        class Callback implements RobustCallBack {
    
            @Override
            public void onPatchListFetched(boolean result, boolean isNet, List<Patch> patches) {
                Log.i("robust","robust arrived in onPatchListFetched");
            }
    
            @Override
            public void onPatchFetched(boolean result, boolean isNet, Patch patch) {
                Log.i("robust","robust arrived in onPatchFetched");
            }
    
            @Override
            public void onPatchApplied(boolean result, Patch patch) {
                Log.i("robust","robust arrived in onPatchApplied");
    
            }
    
            @Override
            public void logNotify(String log, String where) {
                Log.i("robust"," robust arrived in logNotify " + where);
            }
    
            @Override
            public void exceptionNotify(Throwable throwable, String where) {
                throwable.printStackTrace();
                Log.i("robust"," robust arrived in exceptionNotify " + where);
            }
        }
    

    7、执行gradle命令生成APK,将生成好的APK安装到手机中。

    gradlew clean  assembleRelease --stacktrace --no-daemon
    

    8、将app根目录新建robust文件夹,并将app/build/outputs/robust/methodsMap.robust文件拷贝过去。
    9、生成补丁,在代码有修改的方法上加入注解@Modify,如下:

        @Modify
        private String getData(){
            String data = "";
            for (int i=0;i<10;i++){
                data+=(i+"aaaaaaaaaaaaaaa");
            }
            return  data;
        }
    

    10、将App的build.gradle 改为如下后再执行刚刚的gradl命令生成补丁。

    apply plugin: 'com.android.application'
    //制作补丁时将这个打开,auto-patch-plugin紧跟着com.android.application
    apply plugin: 'auto-patch-plugin'
    //apply plugin: 'robust'
    

    11、执行gradle命令后报错没关系,有如下信息表示补丁生成成功了。

    image.png

    12、将补丁app\build\outputs\robust\patch.jar拷贝到手机目录,目录位置为PatchManipulateImp代码中设置的位置

    //这里面需要设置一些补丁的信息,主要是联网的获取的补丁信息。重要的如MD5,进行原始补丁文件的简单校验,以及补丁存储的位置,这边推荐把补丁的储存位置放置到应用的私有目录下,保证安全性
            patch.setLocalPath(Environment.getExternalStorageDirectory().getPath()+ File.separator+"robust"+ File.separator + "patch");
    

    相关文章

      网友评论

          本文标题:Robust热更应用在APP项目

          本文链接:https://www.haomeiwen.com/subject/pvngxftx.html