From eae0414cb494f4a8e37de0bced9b3eaaf71df132 Mon Sep 17 00:00:00 2001 From: huangzhuanghua <401742778@qq.com> Date: Thu, 2 Mar 2017 10:28:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=A0=87=E7=AD=BE=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8Ctinker=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 25 +- app/src/main/AndroidManifest.xml | 6 +- .../main/java/com/gh/base/AppController.java | 6 + .../java/com/gh/base/AppControllerLike.java | 51 +++ .../com/gh/base/AppTinkerResultService.java | 29 ++ .../com/gh/common/util/GameViewUtils.java | 1 - .../java/com/gh/gamecenter/MainActivity.java | 30 -- .../gh/gamecenter/MessageDetailActivity.java | 1 - .../com/gh/gamecenter/SettingActivity.java | 13 - .../download/GameDownloadFragmentAdapter.java | 2 - .../gamedetail/GameDetailAdapter.java | 53 +-- .../gh/gamecenter/retrofit/ApiService.java | 3 - app/src/main/res/layout/activity_setting.xml | 18 - app/tinker-support.gradle | 323 ++++++++++++++++++ build.gradle | 1 + gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 17 files changed, 469 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/com/gh/base/AppControllerLike.java create mode 100644 app/src/main/java/com/gh/base/AppTinkerResultService.java create mode 100644 app/tinker-support.gradle diff --git a/app/build.gradle b/app/build.gradle index 303bc4f8f4..4cd3a0f176 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,15 +4,18 @@ android { compileSdkVersion 21 buildToolsVersion "23.0.3" + dexOptions { + jumboMode = true + } + defaultConfig { applicationId "com.gh.gamecenter" minSdkVersion 14 targetSdkVersion 21 - versionCode 18 - versionName "2.3" + versionCode 19 + versionName "2.4" - // 默认的渠道 -// manifestPlaceholders = [CHANNEL_VALUE: "GH_TEST"] + multiDexEnabled true } /** @@ -39,6 +42,12 @@ android { } } + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + /** * 多渠道打包 */ @@ -129,4 +138,10 @@ dependencies { // zxing 二维码扫描以及生成 compile 'com.google.zxing:core:3.2.1' compile 'com.google.zxing:android-core:3.2.1' -} \ No newline at end of file + //tinker +// compile("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true } +// compile "com.android.support:multidex:1.0.1" +} + +// 依赖插件脚本 +//apply from: 'tinker-support.gradle' \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 115da16725..cc54039eae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -299,8 +299,12 @@ + + + + + android:name="com.gh.gamecenter.statistics.AppStaticService" /> >(){ @@ -608,30 +607,38 @@ public class GameDetailAdapter extends RecyclerView.Adapter { tv_content.setText(gameDetailEntity.getTips().getContent()); viewHolder.gamedetail_ll_plugin_colse.addView(view); } - for (int i = 0, size = tags.size(); i < size; i++) { - view = View.inflate(context, R.layout.gamedetail_plugin_item, null); - iv_hint = (SimpleDraweeView) view.findViewById(R.id.gamedetail_iv_hint); - tv_hint = (TextView) view.findViewById(R.id.gamedetail_tv_hint); - tv_content = (TextView) view.findViewById(R.id.gamedetail_tv_content); - tagEntity = tags.get(i); - tv_content.setText(tagEntity.getDes()); - tv_hint.setText(tagEntity.getName()); + + if (tags.isEmpty()) { + viewHolder.open_plugin_detail_ll.setVisibility(View.GONE); + } else { + viewHolder.open_plugin_detail_ll.setVisibility(View.VISIBLE); + + for (int i = 0, size = tags.size(); i < size; i++) { + view = View.inflate(context, R.layout.gamedetail_plugin_item, null); + iv_hint = (SimpleDraweeView) view.findViewById(R.id.gamedetail_iv_hint); + tv_hint = (TextView) view.findViewById(R.id.gamedetail_tv_hint); + tv_content = (TextView) view.findViewById(R.id.gamedetail_tv_content); + tagEntity = tags.get(i); + tv_content.setText(tagEntity.getDes()); + tv_hint.setText(tagEntity.getName()); // iv_hint.setImageURI(tagEntity.getIcon()); - ImageUtils.display(iv_hint, tagEntity.getIcon()); - viewHolder.gamedetail_ll_plugin.addView(view); + ImageUtils.display(iv_hint, tagEntity.getIcon()); + viewHolder.gamedetail_ll_plugin.addView(view); + } + + RecyclerView recyclerView = new RecyclerView(context); + recyclerView.setLayoutManager(new GridLayoutManager(context, 3)); + + int index = (int) Math.ceil(tags.size() / 3.0); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(context, index * 28)); + params.setMargins(0, DisplayUtils.dip2px(context, index * 3), 0, 0); + + recyclerView.setLayoutParams(params); + recyclerView.setAdapter(new PluginAdapter(tags)); + viewHolder.gamedetail_ll_plugin_colse.addView(recyclerView); } - RecyclerView recyclerView = new RecyclerView(context); - recyclerView.setLayoutManager(new GridLayoutManager(context, 3)); - - int index = (int) Math.ceil(tags.size() / 3.0); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(context, index * 28)); - params.setMargins(0, DisplayUtils.dip2px(context, index * 3), 0, 0); - - recyclerView.setLayoutParams(params); - recyclerView.setAdapter(new PluginAdapter(tags)); - viewHolder.gamedetail_ll_plugin_colse.addView(recyclerView); } } diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/ApiService.java index 22a3f4a032..c6d9bfbe41 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/ApiService.java @@ -78,9 +78,6 @@ public interface ApiService { Observable getGameUpdate(@Path("gh_id") String gh_id, @Path("package_name") String package_name);// 获取游戏更新 - @GET("disclaimer") - Observable getDisclaimer(); // 获取免责声明 - @GET("search/game/default") Observable> getSearchHints(); // 获取搜索关键字 diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml index dae50be70e..800f3b267d 100644 --- a/app/src/main/res/layout/activity_setting.xml +++ b/app/src/main/res/layout/activity_setting.xml @@ -348,24 +348,6 @@ android:textSize="12sp" /> - - - - diff --git a/app/tinker-support.gradle b/app/tinker-support.gradle new file mode 100644 index 0000000000..d39f9c8f6a --- /dev/null +++ b/app/tinker-support.gradle @@ -0,0 +1,323 @@ +def bakPath = file("${buildDir}/bakApk/") +def bakName = "app-debug-0221-18-28-55" + +/** + * 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 = false + + tinkerId = "base_${android.defaultConfig.versionName}" +// tinkerId = "patch_${android.defaultConfig.versionName}" + + //for normal build + //old apk file to build patch apk + tinkerOldApkPath = "${bakPath}/${bakName}.apk" + //proguard mapping file to build patch apk + tinkerApplyMappingPath = "${bakPath}/${bakName}-mapping.txt" + //resource R.txt to build patch apk, must input if there is resource changed + tinkerApplyResourcePath = "${bakPath}/${bakName}-R.txt" + + //only use for build all flavor, if not, just ignore this field + tinkerBuildFlavorDirectory = "${bakPath}/app-0222-11-57-06" +} + +def getOldApkPath() { + return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath +} + +def getApplyMappingPath() { + return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath +} + +def getApplyResourceMappingPath() { + return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath +} + +def getTinkerIdValue() { + return hasProperty("TINKER_ID") ? TINKER_ID : ext.tinkerId +} + +def buildWithTinker() { + return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled +} + +def getTinkerBuildFlavorDirectory() { + return ext.tinkerBuildFlavorDirectory +} + +if (buildWithTinker()) { + apply plugin: 'com.tencent.tinker.patch' + + tinkerPatch { + /** + * necessary,default 'null' + * the old apk path, use to diff with the new apk to build + * add apk from the build/bakApk + */ + oldApk = getOldApkPath() + /** + * optional,default 'false' + * there are some cases we may get some warnings + * if ignoreWarning is true, we would just assert the patch process + * case 1: minSdkVersion is below 14, but you are using dexMode with raw. + * it must be crash when load. + * case 2: newly added Android Component in AndroidManifest.xml, + * it must be crash when load. + * case 3: loader classes in dex.loader{} are not keep in the main dex, + * it must be let tinker not work. + * case 4: loader classes in dex.loader{} changes, + * loader classes is ues to load patch dex. it is useless to change them. + * it won't crash, but these changes can't effect. you may ignore it + * case 5: resources.arsc has changed, but we don't use applyResourceMapping to build + */ + ignoreWarning = false + + /** + * optional,default 'true' + * whether sign the patch file + * if not, you must do yourself. otherwise it can't check success during the patch loading + * we will use the sign config with your build type + */ + useSign = true + + /** + * optional,default 'true' + * whether use tinker to build + */ + tinkerEnable = buildWithTinker() + + /** + * Warning, applyMapping will affect the normal android build! + */ + buildConfig { + /** + * optional,default 'null' + * if we use tinkerPatch to build the patch apk, you'd better to apply the old + * apk mapping file if minifyEnabled is enable! + * Warning: + * you must be careful that it will affect the normal assemble build! + */ + applyMapping = getApplyMappingPath() + /** + * optional,default 'null' + * It is nice to keep the resource id from R.txt file to reduce java changes + */ + applyResourceMapping = getApplyResourceMappingPath() + + /** + * necessary,default 'null' + * because we don't want to check the base apk with md5 in the runtime(it is slow) + * tinkerId is use to identify the unique base apk when the patch is tried to apply. + * we can use git rev, svn rev or simply versionCode. + * we will gen the tinkerId in your manifest automatic + */ + tinkerId = getTinkerIdValue() + + /** + * if keepDexApply is true, class in which dex refer to the old apk. + * open this can reduce the dex diff file size. + */ + keepDexApply = false + } + + dex { + /** + * optional,default 'jar' + * only can be 'raw' or 'jar'. for raw, we would keep its original format + * for jar, we would repack dexes with zip format. + * if you want to support below 14, you must use jar + * or you want to save rom or check quicker, you can use raw mode also + */ + dexMode = "jar" + + /** + * necessary,default '[]' + * what dexes in apk are expected to deal with tinkerPatch + * it support * or ? pattern. + */ + pattern = ["classes*.dex", + "assets/secondary-dex-?.jar"] + /** + * necessary,default '[]' + * Warning, it is very very important, loader classes can't change with patch. + * thus, they will be removed from patch dexes. + * you must put the following class into main dex. + * Simply, you should add your own application {@code tinker.sample.android.SampleApplication} + * own tinkerLoader, and the classes you use in them + * + */ + loader = [ + //use sample, let BaseBuildInfo unchangeable with tinker + "tinker.sample.android.app.BaseBuildInfo" + ] + } + + lib { + /** + * optional,default '[]' + * what library in apk are expected to deal with tinkerPatch + * it support * or ? pattern. + * for library in assets, we would just recover them in the patch directory + * you can get them in TinkerLoadResult with Tinker + */ + pattern = ["lib/*/*.so"] + } + + res { + /** + * optional,default '[]' + * what resource in apk are expected to deal with tinkerPatch + * it support * or ? pattern. + * you must include all your resources in apk here, + * otherwise, they won't repack in the new apk resources. + */ + pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] + + /** + * optional,default '[]' + * the resource file exclude patterns, ignore add, delete or modify resource change + * it support * or ? pattern. + * Warning, we can only use for files no relative with resources.arsc + */ + ignoreChange = ["assets/sample_meta.txt"] + + /** + * default 100kb + * for modify resource, if it is larger than 'largeModSize' + * we would like to use bsdiff algorithm to reduce patch file size + */ + largeModSize = 100 + } + + packageConfig { + /** + * optional,default 'TINKER_ID, TINKER_ID_VALUE' 'NEW_TINKER_ID, NEW_TINKER_ID_VALUE' + * package meta file gen. path is assets/package_meta.txt in patch file + * you can use securityCheck.getPackageProperties() in your ownPackageCheck method + * or TinkerLoadResult.getPackageConfigByName + * we will get the TINKER_ID from the old apk manifest for you automatic, + * other config files (such as patchMessage below)is not necessary + */ + configField("patchMessage", "tinker is sample to use") + /** + * just a sample case, you can use such as sdkVersion, brand, channel... + * you can parse it in the SamplePatchListener. + * Then you can use patch conditional! + */ + configField("platform", "all") + /** + * patch version via packageConfig + */ + configField("patchVersion", "1.0") + } + //or you can add config filed outside, or get meta value from old apk + //project.tinkerPatch.packageConfig.configField("test1", project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test")) + //project.tinkerPatch.packageConfig.configField("test2", "sample") + + /** + * if you don't use zipArtifact or path, we just use 7za to try + */ + sevenZip { + /** + * optional,default '7za' + * the 7zip artifact path, it will use the right 7za with your platform + */ + zipArtifact = "com.tencent.mm:SevenZip:1.1.10" + /** + * optional,default '7za' + * you can specify the 7za path yourself, it will overwrite the zipArtifact value + */ +// path = "/usr/local/bin/7za" + } + } + + List flavors = new ArrayList<>(); + project.android.productFlavors.each {flavor -> + flavors.add(flavor.name) + } + boolean hasFlavors = flavors.size() > 0 + /** + * bak apk and mapping + */ + android.applicationVariants.all { variant -> + /** + * task type, you want to bak + */ + def taskName = variant.name + def date = new Date().format("MMdd-HH-mm-ss") + + 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.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" + } + + } + } + } + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index be515a81ff..ff5371e15b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' +// classpath "com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle.properties b/gradle.properties index 1d3591c8a4..70c772bb23 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,6 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true + +TINKER_VERSION=1.7.7 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 536153e104..1e9bda3694 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Mon May 09 15:17:13 CST 2016 +#Wed Mar 01 17:16:39 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME