美文网首页热修复
AndFix组件化封装

AndFix组件化封装

作者: 小楠总 | 来源:发表于2017-11-30 10:05 被阅读178次

    前言

    为了防止框架的引入对自身项目代码的入侵,我们有必要对引入的框架利用组件化的思想进行一次封装。除了防止代码入侵以外,同时也简化了使用,实现了项目的需求。

    原理

    正所谓开具一张图,内容全靠写,先来看一下封装之后代码的整体流程:

    AndFix组件化封装.png

    主要的核心思想是:

    1. 创建一个后台的FixService
    2. 在进入APP的时候(闪屏页)启动
    3. 然后请求服务器,服务器返回是否有Patch
    4. 如果有Patch,就进行下载、Fix;如果没有Patch,就结束FixService

    封装过程

    为了防止代码入侵、简化使用,我们先来封装一个FixManager,专门用来管理热修复相关的逻辑。有了FixManager,以后替换框架的时候,也不会影响项目的其他代码了。

    下面来看看FixManager的代码:

    public class FixManager {
    
        private static FixManager sInstance;
        private PatchManager mPatchManager;
    
        private FixManager() {}
    
        public static FixManager getInstance() {
            if (sInstance == null) {
                synchronized (FixManager.class) {
                    if (sInstance == null) {
                        sInstance = new FixManager();
                    }
                }
            }
            return sInstance;
        }
    
        public void init(Context context) {
            mPatchManager = new PatchManager(context);
            mPatchManager.init(Utils.getVersionName(context));
            mPatchManager.loadPatch();
        }
    
        public void addPatch(String path) {
            try {
                mPatchManager.addPatch(path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    我们通过单例的形式对FixManager进行封装,这是组件化、同时也是外观设计模式的应用。

    这里主要提供了init以及addPatch方法,分别用于初始化热修复框架、添加Patch进行热修复。

    我们的核心逻辑主要在FixService里面。代码如下:

    public class FixService extends Service {
    
        private static final String TAG = FixService.class.getSimpleName();
        private String mPatchDir;
        private String mPatchFileName;
        private static final String PATCH_FILE_END = ".apatch";
    
        private static final int MSG_CHECK_UPDATE = 0x01;
        private static final int MSG_DOWNLOAD_PATCH = 0x02;
    
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_CHECK_UPDATE:
                        checkHasPatch();
                        break;
                    case MSG_DOWNLOAD_PATCH:
                        downloadPatch();
                        break;
                    default:
                        break;
    
                }
            }
        };
    
        private BasePatch mBasePatch;
    
        @Override
        public IBinder onBind(Intent intent) {
            throw null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            init();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
    
            mHandler.sendEmptyMessage(MSG_CHECK_UPDATE);
    
            //返回START_STICKY表示服务不会自动重启
            return START_STICKY;
        }
    
        private void init() {
            mPatchDir = getExternalCacheDir().getAbsolutePath() + "/patch/";
            File patchFile = new File(mPatchDir);
            if (!patchFile.exists()) {
                patchFile.mkdirs();
            }
        }
    
        private void checkHasPatch() {
            RequestCenter.requestPatchUpdateInfo(new DisposeDataListener() {
                @Override
                public void onSuccess(Object responseObj) {
                    mBasePatch = (BasePatch) responseObj;
                    if (!TextUtils.isEmpty(mBasePatch.data.downloadUrl)) {
                        Log.e(TAG, "onSuccess: " + "has new patch file");
                        mHandler.sendEmptyMessage(MSG_DOWNLOAD_PATCH);
                    } else {
                        stopSelf();
                    }
                }
    
                @Override
                public void onFailure(Object reasonObj) {
                    Log.e(TAG, "onFailure: " + "has no patch file");
                    stopSelf();
                }
            });
        }
    
        private void downloadPatch() {
            mPatchFileName = mPatchDir + System.currentTimeMillis() + PATCH_FILE_END;
            Log.e(TAG, "downloadPatch: " + mPatchFileName);
            RequestCenter.downloadFile(mBasePatch.data.downloadUrl, "mPatchFileName", new DisposeDownloadListener() {
                @Override
                public void onProgress(int progress) {
                    Log.e(TAG, "onProgress: " + progress + "%");
                }
    
                @Override
                public void onSuccess(Object responseObj) {
                    Log.e(TAG, "onSuccess: " + "正在更新");
                    FixManager.getInstance().addPatch(mPatchFileName);
                }
    
                @Override
                public void onFailure(Object reasonObj) {
                    stopSelf();
                }
            });
        }
    }
    

    FixService的封装主要是实现了上图的逻辑过程,主要的操作都通过Handler进行统一处理。代码比较简单就不详细介绍了,需要注意的是:在实际开发的时候,需要把网络请求、Bean等代码替换为自己的即可。

    在项目中使用

    使用上述的封装的时候,需要先在Application中进行初始化:

    public class App extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            FixManager.getInstance().init(this);
        }
    }
    

    然后,在SplashActivity里面开启FixService,那么Fix逻辑就会在Service中执行了。

    public class SplashActivity extends AppCompatActivity {
    
        private Handler mHandler = new Handler();
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
    
            Intent fixIntent = new Intent(SplashActivity.this, FixService.class);
            startService(fixIntent);
    
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent mainIntent = new Intent(SplashActivity.this, MainActivity.class);
                    startActivity(mainIntent);
                }
            }, 2000);
        }
    }
    

    AndFix的优劣

    最后,我们回过头来聊聊AndFix的优劣:

    1. AndFix的优势是:原理简单、集成简单、使用简单、即时生效
    2. AndFix的不足是:只能修复方法级别的BUG,限制了使用场景,例如不能进行资源、Field等的修改。

    相关文章

      网友评论

        本文标题:AndFix组件化封装

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