微信から来た地精修繕師--Tinker

11082 ワード

前言
最近の会社の新しいプロジェクトでは、エンジェルユーザーの試用段階で毎日さまざまなニーズが変更されています.1つのバージョンを変更して1つのバージョンを変更するのは本当に苦しくて、多くの場合はインタフェースの調整の変更、取引結果のレイアウトなどの問題だけです.なにしろ高頻度で実質的な変化のない更新は反感を買うので、改善策を考えなければなりません.そこでホットアップデート技術にアクセスすることを決定し,小さな問題はパッチパッケージ方式を採用した.定期的にリリースされたバージョンは、変更を全体的に反復します.Androidホットアップデート技術はすでに多くのフレームワークが直接使用できるようになっており、どのように仁見智を選択し、自分のプロジェクトに適した方法を選択するかについては.本文は主に私自身のプロジェクトが微信のTinker熱修復フレームワークにアクセスする過程を記録した.
使用前に必ずWikiドキュメントとsampleのコードをよく読んでください!!!Tinker Githubアドレス
クイックアクセスプロセス
一、参考Tinker-アクセスガイド項目に依存するbuildを導入する.gradleで追加
    repositories {
    //mavenLocal        ,               
        mavenLocal()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.1'
        //  Tinker,   
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.0')
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
    allprojects {
        repositories {
            mavenLocal()
            jcenter()
        }
    }

APPのbuild.gradleで追加
    dependencies {
        //  ,    application ,(           )
        compile('com.tencent.tinker:tinker-android-anno:1.7.0')
        //tinker    
        compile('com.tencent.tinker:tinker-android-lib:1.7.0') 
    }
    ...
    ...
    //apply tinker  
    apply plugin: 'com.tencent.tinker.patch'
}

二、その他の構成の比較的速いアクセス方式は自分のappのbuildを直接比較することである.gradleファイルとsampleプロジェクトのbuild.gradleファイルは、独自の構成とtinkerに必要な構成を統合します.defaultConfigのアプリケーションIDを自分のパッケージ名に変更し、signConfigの署名ファイルパス(Gradleパッケージ署名用)に注意します.tinkerPatchのloader配列のApplicationを独自のApplicationに変更します.build.gradleの各構成の解釈wikiドキュメントには説明があります.ここでは、アクセス時に遭遇したいくつかの問題について説明します(ドキュメントにも説明がありますが、ドキュメントをよく見ないと必ず発生する問題です).
  • 1.tinkerIdの問題
  • TinkerIdエラー
    プロジェクトがgitとcommitを初期化していない場合、公式sampleがgit cloneで取得されていない場合もこの問題があります.sample構成では
        tinkerId = getTinkerIdValue()
        ...
        ...
        def getTinkerIdValue() {
            return hasProperty("TINKER_ID") ? TINKER_ID : gitSha()
        }
    

    gitのバージョンshaでtinkerIdを設定します.解決策:1任意の文字列を直接設定する②gitを初期化して1回コミットする.パッチの混乱を回避するために、各ベースパッケージのリリースバージョン(パッチのリリースごとではない)は一意のtinkerIdに対応し、パッチ適用時にパッチとベースパッケージはtinkerIdに関連付けられます.リリース版のgitバージョン番号またはversionNameをtinkerIdとして使用できます.私自身はtinkerIdのこのようなバージョンとしてidに対応するバージョン番号を試用しています.
    //  tinkerid  
    def getTinkerIdValue() {
        return android.defaultConfig.versionName
    }
    
  • 2.keep_in_main_dex.txtで見つからない問題
  •     /**
        * not like proguard, multiDexKeepProguard is not a list, so we can't just
        * add for you in our task. you can copy tinker keep rules at
        * build/intermediates/tinker_intermediates/tinker_multidexkeep.pro
        */
        multiDexKeepProguard file("keep_in_main_dex.txt")
    

    sampleのcopyからの構成には上のようなものがあり、sampleの対応目にもこのファイルがあります.中にはkeepルールがあり、txtファイルを自分のプロジェクト対応ディレクトリにコピーすればいいです.
  • 3.注意しなければならないのはtinkerプラグインがファイルを読み書きする権限を必要とすることです.Android 6.0以下のmianfestで構成すればよいが、6.0以降はJavaコードで権限を申請する必要がある.
  •     
        
    
  • 4.bapApkディレクトリの下でmappingファイルを生成できない問題
  • a.
        /**
        * task type, you want to bak
        * taskName           
        */
        def taskName = "release"
        
    

    b.Android Studioメニューバーbuildを直接使用してパッケージ化する場合もこのような問題が発生します.ここでgradleコマンドを使用してパッケージ化します.
    Gradleパッケージング手順
    Android Studioの右側のバーをクリックしてGradleコマンドメニューを開き、build接点を図のように展開し、構成されたtaskNameに基づいてdebug方式かrelease方式かを選択してパッケージ化し、release方式はリリースするパッケージバージョンです.署名したapkをパッケージ化するにはappのgradleを構成する必要がある.buildの署名ファイル情報
        /**
         * Gradle      
         */
        signingConfigs {
            release {
                storeFile file('E:/PandaQ/tinkerDemo/test.jks')
                keyAlias 'tinker  '
                keyPassword 'tinkertest'
                storePassword 'tinkertest'
            }
            debug {
                storeFile file('C:/Users/PandaQ/.android/debug.keystore')
            }
        }
    

    構成後gradleパッケージングコマンドを実行すると、上の署名ファイルでアプリケーションがパッケージングされますが、署名ファイルのパスワードを直接構成に置くのは安全ではありません.パッケージング中に入力するように設定できます.具体的にはこちらをご覧ください
  • 5.cleanまたはrebuildエンジニアリング後bakApkフォルダがクリアされた問題パッチをパッケージングする際にインフラストラクチャを構成する必要があるため:
  •     /**
     * you can use assembleRelease to build you base apk
     * use tinkerPatchRelease -POLD_APK=  -PAPPLY_MAPPING=  -PAPPLY_RESOURCE= to build patch
     * add apk from the build/bakApk
     */
    ext {
        //for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
        tinkerEnabled = true
        //you should bak the following files
        //old apk file to build patch apk
        //app-debug-1017-11-29-32.apk
        tinkerOldApkPath = "${bakPath}/app-release-1024-16-46-49.apk"
        //proguard mapping file to build patch apk
        tinkerApplyMappingPath = "${bakPath}/app-release-1024-16-46-49-mapping.txt"
        //resource R.txt to build patch apk, must input if there is resource changed
        tinkerApplyResourcePath = "${bakPath}/app-release-1024-16-46-49-R.txt"
    }
    

    デフォルトの出力ディレクトリはbakApkディレクトリですが、cleanまたはrebuildエンジニアリングのたびにこのフォルダがクリーンアップされるため、手動 mapping.txt R.txt が必要です.またはGradle構成の出力ディレクトリを変更します.三、アプリケーション類参考Tinker-カスタム拡張
    公式ドキュメントのスクリーンショット
    Tinkerのアクセスドキュメントでは、アプリケーションクラスについて説明しています.実際のアプリケーションを変更できるように、アプリケーションのすべてのロジックをアプリケーションLikeエージェントクラスに移動します.ApplicationはTinkerApplicationを継承して1つのsuperの空の実装を行うか、ApplicationLikeエージェントに注釈を追加して直接動的にApplicationクラスを生成することで、うっかり他のコードが書かれないようにします.
    @DefaultLifeCycle(
            application = "com.seuic.seuickp.KPApplication",             //application name to generate
            flags = ShareConstants.TINKER_ENABLE_ALL)
    public class KPApplicationLike extends DefaultApplicationLike {
    
        public static Context mContext;
        public static ImageLoader mImageLoader;
        public static DisplayImageOptions sOptions;
    
        public KPApplicationLike(Application application, int tinkerFlags, 
        boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime,Intent tinkerResultIntent, Resources[] resources, ClassLoader[] classLoader, AssetManager[] assetManager) {
            super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime,tinkerResultIntent, resources, classLoader, assetManager);
        }
    
        @Override
        public void onBaseContextAttached(Context base) {
            super.onBaseContextAttached(base);
            MultiDex.install(base);
            TinkerManager.setTinkerApplicationLike(this);
            TinkerManager.installTinker(this);
        }
    
        public static ImageLoader getmImageLoader() {
            return mImageLoader;
        }
    
        public static DisplayImageOptions getOptions() {
            return sOptions;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            mContext = getApplication().getApplicationContext();
            DBTools.init(mContext);
            mImageLoader = ImageLoader.getInstance();
            ImageLoaderConfiguration config = new ImageLoaderConfiguration
                    .Builder(mContext)
                    .threadPoolSize(4)
                    .imageDownloader(new AuthImageDownloader(getApplication().getApplicationContext()))
                    .build();
            mImageLoader.init(config);
            sOptions = new DisplayImageOptions
                    .Builder()
                    .showImageForEmptyUri(R.drawable.loading_pic)
                    .showImageOnFail(R.drawable.loading_pic)
                    .showImageOnLoading(R.drawable.loading_pic)
                    .cacheInMemory(true)
                    .cacheOnDisk(true)
    //                .displayer(new RoundedBitmapDisplayer(10))
                    .build();
            //     Bugly
            CrashReport.initCrashReport(getApplication().getApplicationContext(), "900053571", false);
        }
    
        public static Context getContext() {
            return mContext;
        }
    
        public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
            getApplication().registerActivityLifecycleCallbacks(callback);
        }
    }
    

    上はtinkerの小さなプロジェクトのApplicationにアクセスし、Applicationのoncreate()メソッドをApplicationLikeに直接移動し、onBaseContextAttached()メソッドでtinkerを初期化します.その後、Applicationに関するすべての参照をApplicationLike.getApplication()に変更すればよい.
    上記の操作を完了すると、構成部分は基本的に完了し、次にパッケージの更新をテストすることができます.
    パッケージテスト
    プロファイルに基づいてGradleのbuildで適切なパッケージ方法(上の図に表示されている)を選択し、パッケージ後にデフォルトの出力パスを変更しない場合、bakAPKフォルダとoutputsフォルダはエンジニアリングapp->buildディレクトリの下で生産されます.
    注意bakapkとoutputs
  • a bakAPKの3つのファイルをバックアップすることが重要です!パッチの生成に必要な
  • b outputs-->abp-->app-release.apkはリリースが必要なバージョン
  • です.
  • cパッケージングパッチ:bakApkのファイルをbuildに構成します.gradle中
  •     /**
     * you can use assembleRelease to build you base apk
     * use tinkerPatchRelease -POLD_APK=  -PAPPLY_MAPPING=  -PAPPLY_RESOURCE= to build patch
     * add apk from the build/bakApk
     */
    ext {
        //for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
        tinkerEnabled = true
        //you should bak the following files
        //old apk file to build patch apk
        //app-debug-1017-11-29-32.apk
        tinkerOldApkPath = "${bakPath}/app-debug-1024-20-00-21.apk"
        //proguard mapping file to build patch apk
        tinkerApplyMappingPath = "${bakPath}/app-release-1024-20-02-47-mapping.txt"
        //resource R.txt to build patch apk, must input if there is resource changed
        tinkerApplyResourcePath = "${bakPath}/app-debug-1024-20-00-21-R.txt"
    }
    

    メソッドのみを変更する場合はOldApkPathを構成するだけでよい、リソースファイルを変更する場合はmappingを構成する必要がある.txtとR.txt
  • d Gradle->tinker-->tinkerPatchRelease/Debugパッケージング生成パッチを選択し、パッケージング後outputsでtinkerPatchフォルダを生成し、生成されたpatch_signed.apkまたはpatch_signed_7zip.apk(選択が小さい)は携帯電話のファイルシステムにプッシュされる(ファイル名はapkで終わらなくてもよい).
  • eサービス中またはイベントコールによるパッチのロード
  •         loadPatchButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), Environment.getExternalStorageDirectory().getAbsolutePath() + "/seuic/kp/patch_signed_7zip.apk");
                }
            });
    

    デフォルトでtinkerを初期化するには、TinkerInstallerクラスのinstall()メソッドを表示する2つの方法があります.ResultServiceが指定されていない場合はDefaultResultServiceを使用します.ロードに成功すると、自動的にプロセスアプリケーションが終了し、直接閉じます.明らかに友好的ではないので、DefaultResultServiceを継承し、パッチのロードが完了した後に行う操作を書き換えることができます(パッチのロード後にプロセスの再起動が必要なため、ダイアログを開いてユーザーを再起動させることができます).
  • f 1つのベースパッケージは複数回のパッチを適用することができ、不定期構成のoldApkは常にベースパッケージであり、前のパッチパッケージを後のパッチのoldApkとして使用することはできない.

  • 上はtinkerホットアップデートにアクセスするすべてのステップです.より多くのシーンやアクセスが必要です.tinkerのソースコードを研究したり、githubのwikiドキュメントをよく見たりすることは、一般的によくある問題と解決できます.
    Tinker倉庫住所