Tinker自动热更新


 //project配置
buildscript {
    dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
    }
}
//app/build.gradle 配置
dependencies {
    //optional, help to generate the final application 
    provided('com.tencent.tinker:tinker-android-anno:1.9.1')
    //tinker's main Android lib
    compile('com.tencent.tinker:tinker-android-lib:1.9.1')
}
...
...
apply plugin: 'com.tencent.tinker.patch'
//如下实例
apply plugin: 'com.android.application'
apply plugin: 'com.tencent.tinker.patch'


android {
    signingConfigs {
        release {
            keyAlias 'key0'
            keyPassword '123456'
            storeFile file('/Users/eric/Downloads/Tinker/app/tinker.jks')
            storePassword '123456'
        }
    }
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.xieast.tinker"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath true
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}


dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    //可选,用于生成application类
    provided 'com.tencent.tinker:tinker-android-anno:1.9.2'
    //tinker的核心库
    compile 'com.tencent.tinker:tinker-android-lib:1.9.2'
    implementation 'com.android.support:multidex:1.0.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

//没更新前的路径 
def bakPath = file("${buildDir}/bakApk/")

ext {
    tinkerOldApkPath  = "${bakPath}/app-release-0605-15-47-00.apk"
}


def getOldApkPath() {
    return ext.tinkerOldApkPath
}

//配置
tinkerPatch {
    tinkerEnable true
    oldApk = getOldApkPath()
    ignoreWarning true
    useSign true


    buildConfig {
        tinkerId = "tinker_id_b168b32"
        keepDexApply = false
        isProtectedApp = false
    }


    dex {
        dexMode = "jar"
        pattern = ["classes*.dex", "assets/secondary-dex-?.jar"]
        loader =  ["com.xieast.tinker.MyTinkerApplication"]
    }


    lib {
        pattern = ["lib/*/*.so"]
    }


    res {
        pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
        largeModSize = 100
    }


    packageConfig {
        configField("patchVersion", "1.0")
    }
}


List<String> flavors = new ArrayList<>();
project.android.productFlavors.each { flavor ->
    flavors.add(flavor.name)
}
boolean hasFlavors = flavors.size() > 0
def date = new Date().format("MMdd-HH-mm-ss")


/**
 * bak apk and mapping
 */
android.applicationVariants.all { variant ->
    /**
     * task type, you want to bak
     */
    def taskName = variant.name


    tasks.all {
        if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {


            it.doLast {
                copy {
                    def fileNamePrefix = "${project.name}-${variant.baseName}"
                    def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}"


                    def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath
                    from variant.outputs.first().outputFile
                    into destPath
                    rename { String fileName ->
                        fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")
                    }


                    from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"
                    into destPath
                    rename { String fileName ->
                        fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")
                    }


                    from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"
                    into destPath
                    rename { String fileName ->
                        fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")
                    }
                }
            }
        }
    }
}
project.afterEvaluate {
    //sample use for build all flavor for one time
    if (hasFlavors) {
        task(tinkerPatchAllFlavorRelease) {
            group = 'tinker'
            def originOldPath = getTinkerBuildFlavorDirectory()
            for (String flavor : flavors) {
                def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release")
                dependsOn tinkerTask
                def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest")
                preAssembleTask.doFirst {
                    String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15)
                    project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk"
//                    project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt"
//                    project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt"


                }


            }
        }


        task(tinkerPatchAllFlavorDebug) {
            group = 'tinker'
            def originOldPath = getTinkerBuildFlavorDirectory()
            for (String flavor : flavors) {
                def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug")
                dependsOn tinkerTask
                def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest")
                preAssembleTask.doFirst {
                    String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13)
                    project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk"
//                    project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt"
//                    project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt"
                }


            }
        }
    }
}

//如果你的应用有一个子类为android.app.Application的类,
那么你需要修改这个类,并将它的所有实现移动到SampleApplicationLike而
不是Application:
现在你应该改变你的Application类,使它成为TinkerApplication的一个子类。
正如你可以从它的API中看到的那样,它是一个没有默认构造函数的抽象类,
所以你必须定义一个无参数构造函数:
建议使用tinker-android-anno生成你Application的,你只需要为你的SampleApplicationLike类添加一个注释
@DefaultLifeCycle(application=".MyTinkerApplication",flags = ShareConstants.TINKER_ENABLE_ALL )
public class MyAppp extends DefaultApplicationLike {
    public MyAppp(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }

    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        MultiDex.install(getApplication().getApplicationContext());
        TinkerManager.insell(this);
    }
}
/**
 *
 TinkerManager 管理类

 */


public class TinkerManager {


    private static boolean isInstalled = false;
    private static ApplicationLike mApplicationLike;


    /**
     * 安装tinker
     *
     * @param applicationLike
     */
    public static void install(ApplicationLike applicationLike) {
        mApplicationLike = applicationLike;
        if (isInstalled) {
            return;
        }
        TinkerInstaller.install(applicationLike);
        isInstalled = true;
    }


    /**
     * 加载补丁
     *
     * @param path
     */
    public static void loadPatch(String path) {
        if (Tinker.isTinkerInstalled()) {
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
        }
    }


    /**
     * 获取上下文
     *
     * @return
     */
    private static Context getApplicationContext() {
        if (mApplicationLike != null) {
            return mApplicationLike.getApplication().getApplicationContext();
        }
        return null;
    }
}
/**
  MainActivity
**/


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";


    private TextView txtShow;
    private Button btnLoad;
    private Button btnNew;
    private Button btnNew2;


    private String patchDir = "patch";


    private String patchName = "tk.apk";


    private File patchFile;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        txtShow = findViewById(R.id.txt_show);
        btnLoad = findViewById(R.id.btn_load_patch);
        btnNew = findViewById(R.id.btn_new_function);
        btnNew2 = findViewById(R.id.btn_new_gradle);
        //获得补丁路径
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File rootDirectory = Environment.getExternalStorageDirectory();
            File patchPath = new File(rootDirectory, patchDir);
            if (!patchPath.exists()) {
                patchPath.mkdirs();
            }


            patchFile = new File(patchPath, patchName);
        }


        btnLoad.setOnClickListener(this);
        btnNew.setOnClickListener(this);
        btnNew2.setOnClickListener(this);


    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_load_patch:
			    //加载补丁
                String path = patchFile.getAbsolutePath();
                Log.i(TAG, "path: " + path);
                TinkerManager.loadPatch(path);
                break;
            case R.id.btn_new_function:
                Toast.makeText(this, "这是新功能", Toast.LENGTH_SHORT).show();
                break;
            case R.id.btn_new_gradle:
                Toast.makeText(this, "这是Gradle打包的", Toast.LENGTH_SHORT).show();
                break;
        }
    }


}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值