Compare commits

...

7 Commits

75 changed files with 885 additions and 635 deletions

View File

@ -5,10 +5,12 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
apply plugin: 'kotlin-kapt'
apply plugin: 'therouter'
apply plugin: 'com.sensorsdata.analytics.android'
import groovy.xml.XmlUtil
android {
namespace 'com.gh.gamecenter'
String CONFIG_ID = ""
String FIRST_LAUNCH = ""
@ -21,6 +23,7 @@ android {
buildFeatures {
viewBinding true
dataBinding true
buildConfig true
}
compileOptions {
@ -183,6 +186,16 @@ android {
flavorDimensions("env", "region")
sensorsAnalytics {
sdk {
disableIMEI = true
disableCarrier = true
disableMacAddress = true
}
disableModules = ['AUTOTRACK', 'PUSH']
}
sourceSets {
debug {

View File

@ -7,6 +7,61 @@
# Keep Attribute
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod,SourceFile,LineNumberTable
# Remove log related code
-assumenosideeffects class android.util.Log {
public static *** v(...);
public static *** d(...);
public static *** i(...);
public static *** w(...);
public static *** e(...);
public static *** println(...);
public static *** isLoggable(...);
}
-assumenosideeffects class java.lang.Throwable {
public *** printStackTrace(...);
}
-assumenosideeffects class java.io.PrintStream {
public *** println(...);
public *** print(...);
}
-assumenosideeffects class com.google.devtools.build.android.desugar.runtime.ThrowableExtension {
public *** printStackTrace(...);
}
-assumenosideeffects class com.lightgame.utils.Utils {
public static *** log(...);
}
-assumenosideeffects class com.gh.gamecenter.core.utils.MtaHelper {
public static *** onEvent(...);
public static *** onEventWithTime(...);
public static *** onEventWithBasicDeviceInfo(...);
}
# Remove all logging calls via JDK Loggers. They are generally from
# unused parts of third-party libraries.
-assumenosideeffects class java.util.logging.Logger {
void finest(...);
void finer(...);
void fine(...);
void info(...);
void warning(...);
void severe(...);
void throwing(...);
void log(...);
void logp(...);
static java.util.logging.Logger getLogger(...) return _NONNULL_;
boolean isLoggable(...) return false;
}
# Remove accesses to Level.<thing> that go unused.
-assumenosideeffects class java.util.logging.Level {
<fields>;
# Flogger uses Level objects, so do not set a return value for intValue().
int intValue();
}
# Remove fields of type Logger.
-assumenosideeffects class * {
java.util.logging.Logger * return _NONNULL_;
}
# OrmLite
-keep class com.j256.*
-keepclassmembers class com.j256.* { *; }

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter">
xmlns:tools="http://schemas.android.com/tools">
<queries>
<package android:name="com.gh.gamecenter" />

View File

@ -16,13 +16,13 @@ import androidx.core.app.NotificationCompat;
import com.blankj.utilcode.util.ThreadUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.ndownload.suspendwindow.NDownloadDrawOverlayPermissionWindowController;
import com.gh.ndownload.suspendwindow.NDownloadSuspendWindowController;
import com.gh.ndownload.suspendwindow.utils.NDownloadSuspendWindowHelper;
import com.lightgame.BuildConfig;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadDao;
import com.lightgame.download.DownloadEntity;

View File

@ -18,16 +18,16 @@ buildscript {
}
dependencies {
classpath "com.android.tools.build:gradle:7.1.3"
classpath 'com.android.tools.build:gradle:8.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:3.5.3'
classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:4.0.6'
classpath "com.lg.shadow.core:gradle-plugin:$shadow_version"
}
}
plugins {
id 'com.google.devtools.ksp' version '1.9.24-1.0.20' apply false
id 'cn.therouter' version '1.2.2' apply false
id 'cn.therouter.agp8' version '1.2.4' apply false
}
apply from: 'dependencies.gradle'
apply from: 'vspace-bridge/config.gradle'
@ -64,6 +64,19 @@ allprojects {
task clean(type: Delete) {
delete rootProject.buildDir
}
subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
buildFeatures {
buildConfig = true
}
}
}
}
}
subprojects {
subproject ->
afterEvaluate {

View File

@ -18,7 +18,7 @@ apply plugin: 'kotlin'
dependencies {
implementation gradleApi()
implementation localGroovy()
implementation "com.android.tools.build:gradle:7.1.3"
implementation 'com.android.tools.build:gradle:8.0.2'
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
implementation "commons-io:commons-io:2.4"
implementation "org.javassist:javassist:3.25.0-GA"

View File

@ -0,0 +1,48 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
abstract class ActivityStartActivityForResultVisitorFactory :
AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor,
): ClassVisitor {
return ActivityStartActivityForResultVisitor(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.contains("androidx.activity.ComponentActivity")
}
}
class ActivityStartActivityForResultVisitor(nextVisitor: ClassVisitor) :
ClassVisitor(Opcodes.ASM9, nextVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?,
): MethodVisitor {
val originalMv = super.visitMethod(access, name, descriptor, signature, exceptions)
// Only modify the run() method
return if (name == "startActivityForResult") {
println("ActivityStartActivityForResultVisitor found startActivityForResult method")
TryCatchMethodVisitor(Opcodes.ASM9, originalMv, access, name, descriptor)
} else {
originalMv
}
}
}

View File

@ -0,0 +1,46 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
abstract class AppCompatEditTextVisitorFactory
: AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor,
): ClassVisitor {
return AppCompatEditTextVisitor(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.contains("androidx.appcompat.widget.AppCompatEditText")
}
}
class AppCompatEditTextVisitor(nextVisitor: ClassVisitor) :
ClassVisitor(Opcodes.ASM9, nextVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?,
): MethodVisitor {
val originalMv = super.visitMethod(access, name, descriptor, signature, exceptions)
return if (name == "onTextContextMenuItem") {
TryCatchMethodVisitor(Opcodes.ASM9, originalMv, access, name, descriptor, true)
} else {
originalMv
}
}
}

View File

@ -0,0 +1,57 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.Opcodes
abstract class DuplicateClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
val className = classContext.currentClassData.className.replace('.', '/')
return DuplicateClassVisitor(nextClassVisitor, className)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return true
}
}
class DuplicateClassVisitor(nextVisitor: ClassVisitor, private val className: String)
: ClassVisitor(Opcodes.ASM9, nextVisitor) {
private val duplicatedPackages = listOf(
"com/google/android/material/chip",
"com/google/android/material/textfield",
"com/google/android/material/navigation",
"com/google/android/material/datepicker",
"com/google/android/material/circularreveal",
"com/google/android/material/timepicker",
"com/google/android/material/divider",
"com/google/android/material/slider",
"com/google/android/material/card",
"com/google/android/material/transformation",
"com/google/android/material/snackbar",
"com/google/android/material/switchmaterial",
"com/google/android/material/bottomappbar",
"com/google/android/material/behavior",
"com/google/android/material/floatingactionbutton",
)
override fun visitEnd() {
val isDuplicated = duplicatedPackages.any { className.contains(it) }
if (isDuplicated) {
println("DuplicateClassVisitor found duplicated class $className")
} else {
super.visitEnd()
}
}
}

View File

@ -1,20 +1,55 @@
package com.gh.gamecenter.plugin
import com.android.build.gradle.AppExtension
import com.android.build.api.instrumentation.FramesComputationMode
import com.android.build.api.instrumentation.InstrumentationScope
import com.android.build.api.variant.AndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class GhPlugin : Plugin<Project> {
override fun apply(project: Project) {
val log = project.logger
log.error("========================")
log.error("光环 transfrom 插件启动")
log.error("========================")
project.extensions.findByType(AppExtension::class.java)?.registerTransform(GhTransform(project))
project.extensions.findByType(AppExtension::class.java)?.registerTransform(PluginAssetTransform())
log.error("========================")
log.error("光环 transfrom 插件结束")
log.error("========================")
val appExtension = project.extensions.getByType(AndroidComponentsExtension::class.java)
appExtension.onVariants { variant ->
// 移除无用的类
// variant.instrumentation.transformClassesWith(
// DuplicateClassVisitorFactory::class.java,
// InstrumentationScope.ALL
// ) {}
// plugin asset 目录处理
variant.instrumentation.transformClassesWith(
PluginAssetClassVisitorFactory::class.java,
InstrumentationScope.ALL
) {}
// Room 闪退 try catch 处理
variant.instrumentation.transformClassesWith(
RoomClassVisitorFactory::class.java,
InstrumentationScope.ALL
) {}
// ComponentActivity startActivityForResult 闪退 try catch 处理
variant.instrumentation.transformClassesWith(
ActivityStartActivityForResultVisitorFactory::class.java,
InstrumentationScope.ALL
) {}
// AppCompatEditText 闪退 try catch 处理 (主要出现在 VIVO 设备上)
variant.instrumentation.transformClassesWith(
AppCompatEditTextVisitorFactory::class.java,
InstrumentationScope.ALL
) {}
// QQ 小游戏获取系统 UA 的处理,避免提前初始化 WebView 导致启动耗时
variant.instrumentation.transformClassesWith(
MiniGameWebViewVisitorFactory::class.java,
InstrumentationScope.ALL
) {}
variant.instrumentation.setAsmFramesComputationMode(FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
}
}
}

View File

@ -1,202 +1,202 @@
package com.gh.gamecenter.plugin
import com.android.build.api.transform.Format
import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformInvocation
import com.android.build.gradle.AppExtension
import com.android.build.gradle.internal.pipeline.TransformManager
import com.gh.gamecenter.plugin.transform.*
import javassist.ClassPool
import org.apache.commons.io.FileUtils
import org.apache.commons.io.IOUtils
import org.gradle.api.Project
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
class GhTransform(var project: Project) : Transform() {
private val mClassPool = ClassPool.getDefault()
private val mTransformHelper = GhTransformHelper()
private val mExcludePackages = listOf(
"com/google/android/material/chip",
"com/google/android/material/textfield",
"com/google/android/material/navigation",
"com/google/android/material/datepicker",
"com/google/android/material/circularreveal",
"com/google/android/material/timepicker",
"com/google/android/material/divider",
"com/google/android/material/slider",
"com/google/android/material/card",
"com/google/android/material/transformation",
"com/google/android/material/snackbar",
"com/google/android/material/switchmaterial",
"com/google/android/material/bottomappbar",
"com/google/android/material/behavior",
"com/google/android/material/floatingactionbutton",
)
override fun getName() = "GhTransform"
init {
mTransformHelper.addTransformer(ExoSourceManagerTransformer())
mTransformHelper.addTransformer(DiskLruCacheTransformer())
mTransformHelper.addTransformer(RoomTransformer())
mTransformHelper.addTransformer(ActivityTransformer())
mTransformHelper.addTransformer(AppCompatEditTextTransformer())
mTransformHelper.addTransformer(MiniGameWebViewTransformer())
}
/**
 * 需要处理的数据类型目前 ContentType有六种枚举类型通常我们使用比较频繁的有前两种
 * 1、CONTENT_CLASS表示需要处理 java  class 文件。
 * 2、CONTENT_JARS表示需要处理 java  class  资源文件。
 * 3、CONTENT_RESOURCES表示需要处理 java 的资源文件。
 * 4、CONTENT_NATIVE_LIBS表示需要处理 native 库的代码。
 * 5、CONTENT_DEX表示需要处理 DEX 文件。
 * 6、CONTENT_DEX_WITH_RESOURCES表示需要处理 DEX  java 的资源文件。 
*/
override fun getInputTypes(): MutableSet<QualifiedContent.ContentType> {
return TransformManager.CONTENT_CLASS
}
/**
* 是否增量编译
*/
// TODO Why not?
override fun isIncremental() = false
/**
 * Transform 要操作的内容范围目前 Scope 有五种基本类型
 * 1、PROJECT只有项目内容
 * 2、SUB_PROJECTS只有子项目
 * 3、EXTERNAL_LIBRARIES只有外部库
 * 4、TESTED_CODE由当前变体包括依赖项所测试的代码
 * 5、PROVIDED_ONLY只提供本地或远程依赖项
 * SCOPE_FULL_PROJECT 是一个Scope集合包含Scope.PROJECT,Scope.SUB_PROJECTS,Scope.EXTERNAL_LIBRARIES 这三项即当前Transform的作用域包括当前项目、子项目以及外部的依赖库
*/
override fun getScopes(): MutableSet<in QualifiedContent.Scope> {
// 通常我们使用 SCOPE_FULL_PROJECT
return TransformManager.SCOPE_FULL_PROJECT
}
override fun transform(transformInvocation: TransformInvocation?) {
super.transform(transformInvocation)
// 添加 android.jar path
mClassPool?.appendClassPath((project.extensions.findByType(AppExtension::class.java)!!.bootClasspath[0].toString()))
val outputProvider = transformInvocation?.outputProvider
outputProvider?.deleteAll()
transformInvocation?.inputs?.forEach { input ->
input.directoryInputs.forEach { dirInput ->
handleDirectory(dirInput.file)
// 将input的目录复制到output指定目录
val dest = outputProvider?.getContentLocation(
dirInput.name,
dirInput.contentTypes,
dirInput.scopes,
Format.DIRECTORY
)
FileUtils.copyDirectory(dirInput.file, dest)
}
}
var index = 0
transformInvocation?.inputs?.forEach { input ->
input.jarInputs.forEach { jarInput ->
if (jarInput.file.exists()) {
val srcFile = handleJar(jarInput.file)
// 必须给jar重新命名否则会冲突
var jarName = jarInput.name
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length - 4)
}
val dest = outputProvider?.getContentLocation(
jarName + "_" + index,
jarInput.contentTypes,
jarInput.scopes,
Format.JAR
)
FileUtils.copyFile(srcFile, dest)
index++
}
}
}
}
private fun handleDirectory(dir: File) {
// 将类路径添加到 classPool 中
mClassPool.insertClassPath(dir.absolutePath)
if (dir.isDirectory) {
dir.walkTopDown().forEach { file ->
val filePath = file.absolutePath
mClassPool.insertClassPath(filePath)
if (shouldModify(filePath)) {
val inputStream = FileInputStream(file)
mTransformHelper.proceedModifyDir(filePath, inputStream)
}
}
}
}
/**
* 主要步骤:
* 1.遍历所有jar文件
* 2.解压jar然后遍历所有的class
* 3.读取class的输入流并使用javassit修改然后保存到新的jar文件中
*/
fun handleJar(jarFile: File): File {
mClassPool.appendClassPath(jarFile.absolutePath)
val inputJarFile = JarFile(jarFile)
val entries = inputJarFile.entries()
//创建一个新的文件
val outputJarFile = File(jarFile.parentFile, "temp_" + jarFile.name)
if (outputJarFile.exists()) outputJarFile.delete()
val jarOutputStream = JarOutputStream(BufferedOutputStream(FileOutputStream(outputJarFile)))
while (entries.hasMoreElements()) {
val jarInputEntry = entries.nextElement()
val jarInputEntryName = jarInputEntry.name
var isIgnore = false
for (i in mExcludePackages.indices){
if (jarInputEntryName.contains(mExcludePackages[i])) {
isIgnore = true
break
}
}
if (isIgnore) continue
val outputJarEntry = JarEntry(jarInputEntryName)
jarOutputStream.putNextEntry(outputJarEntry)
val inputStream = inputJarFile.getInputStream(jarInputEntry)
if (!shouldModify(jarInputEntryName)) {
jarOutputStream.write(IOUtils.toByteArray(inputStream))
inputStream.close()
continue
}
mTransformHelper.proceedModifyJar(jarInputEntryName, jarOutputStream, inputStream)
}
inputJarFile.close()
jarOutputStream.closeEntry()
jarOutputStream.flush()
jarOutputStream.close()
return outputJarFile
}
private fun shouldModify(filePath: String): Boolean {
return filePath.endsWith(".class")
&& !filePath.contains("R.class")
// && !filePath.contains("$")
&& !filePath.contains("R$")
&& !filePath.contains("BuildConfig.class")
}
}
//package com.gh.gamecenter.plugin
//
//import com.android.build.api.transform.Format
//import com.android.build.api.transform.QualifiedContent
//import com.android.build.api.transform.Transform
//import com.android.build.api.transform.TransformInvocation
//import com.android.build.gradle.AppExtension
//import com.android.build.gradle.internal.pipeline.TransformManager
//import com.gh.gamecenter.plugin.transform.*
//import javassist.ClassPool
//import org.apache.commons.io.FileUtils
//import org.apache.commons.io.IOUtils
//import org.gradle.api.Project
//import java.io.BufferedOutputStream
//import java.io.File
//import java.io.FileInputStream
//import java.io.FileOutputStream
//import java.util.jar.JarEntry
//import java.util.jar.JarFile
//import java.util.jar.JarOutputStream
//
//class GhTransform(var project: Project) : Transform() {
//
// private val mClassPool = ClassPool.getDefault()
// private val mTransformHelper = GhTransformHelper()
// private val mExcludePackages = listOf(
// "com/google/android/material/chip",
// "com/google/android/material/textfield",
// "com/google/android/material/navigation",
// "com/google/android/material/datepicker",
// "com/google/android/material/circularreveal",
// "com/google/android/material/timepicker",
// "com/google/android/material/divider",
// "com/google/android/material/slider",
// "com/google/android/material/card",
// "com/google/android/material/transformation",
// "com/google/android/material/snackbar",
// "com/google/android/material/switchmaterial",
// "com/google/android/material/bottomappbar",
// "com/google/android/material/behavior",
// "com/google/android/material/floatingactionbutton",
// )
//
// override fun getName() = "GhTransform"
//
// init {
// mTransformHelper.addTransformer(ExoSourceManagerTransformer())
// mTransformHelper.addTransformer(DiskLruCacheTransformer())
// mTransformHelper.addTransformer(RoomTransformer())
// mTransformHelper.addTransformer(ActivityTransformer())
// mTransformHelper.addTransformer(AppCompatEditTextTransformer())
// mTransformHelper.addTransformer(MiniGameWebViewTransformer())
// }
//
// /**
//  * 需要处理的数据类型目前 ContentType有六种枚举类型通常我们使用比较频繁的有前两种
//  * 1、CONTENT_CLASS表示需要处理 java  class 文件。
//  * 2、CONTENT_JARS表示需要处理 java  class  资源文件。
//  * 3、CONTENT_RESOURCES表示需要处理 java 的资源文件。
//  * 4、CONTENT_NATIVE_LIBS表示需要处理 native 库的代码。
//  * 5、CONTENT_DEX表示需要处理 DEX 文件。
//  * 6、CONTENT_DEX_WITH_RESOURCES表示需要处理 DEX  java 的资源文件。 
// */
// override fun getInputTypes(): MutableSet<QualifiedContent.ContentType> {
// return TransformManager.CONTENT_CLASS
// }
//
// /**
// * 是否增量编译
// */
// // TODO Why not?
// override fun isIncremental() = false
//
// /**
//  * Transform 要操作的内容范围目前 Scope 有五种基本类型
//  * 1、PROJECT只有项目内容
//  * 2、SUB_PROJECTS只有子项目
//  * 3、EXTERNAL_LIBRARIES只有外部库
//  * 4、TESTED_CODE由当前变体包括依赖项所测试的代码
//  * 5、PROVIDED_ONLY只提供本地或远程依赖项
//  * SCOPE_FULL_PROJECT 是一个Scope集合包含Scope.PROJECT,Scope.SUB_PROJECTS,Scope.EXTERNAL_LIBRARIES 这三项即当前Transform的作用域包括当前项目、子项目以及外部的依赖库
// */
// override fun getScopes(): MutableSet<in QualifiedContent.Scope> {
// // 通常我们使用 SCOPE_FULL_PROJECT
// return TransformManager.SCOPE_FULL_PROJECT
// }
//
// override fun transform(transformInvocation: TransformInvocation?) {
// super.transform(transformInvocation)
//
// // 添加 android.jar path
// mClassPool?.appendClassPath((project.extensions.findByType(AppExtension::class.java)!!.bootClasspath[0].toString()))
//
// val outputProvider = transformInvocation?.outputProvider
// outputProvider?.deleteAll()
//
// transformInvocation?.inputs?.forEach { input ->
// input.directoryInputs.forEach { dirInput ->
// handleDirectory(dirInput.file)
//
// // 将input的目录复制到output指定目录
// val dest = outputProvider?.getContentLocation(
// dirInput.name,
// dirInput.contentTypes,
// dirInput.scopes,
// Format.DIRECTORY
// )
// FileUtils.copyDirectory(dirInput.file, dest)
// }
// }
//
// var index = 0
// transformInvocation?.inputs?.forEach { input ->
// input.jarInputs.forEach { jarInput ->
// if (jarInput.file.exists()) {
// val srcFile = handleJar(jarInput.file)
// // 必须给jar重新命名否则会冲突
// var jarName = jarInput.name
// if (jarName.endsWith(".jar")) {
// jarName = jarName.substring(0, jarName.length - 4)
// }
// val dest = outputProvider?.getContentLocation(
// jarName + "_" + index,
// jarInput.contentTypes,
// jarInput.scopes,
// Format.JAR
// )
// FileUtils.copyFile(srcFile, dest)
// index++
// }
// }
// }
// }
//
// private fun handleDirectory(dir: File) {
// // 将类路径添加到 classPool 中
// mClassPool.insertClassPath(dir.absolutePath)
//
// if (dir.isDirectory) {
// dir.walkTopDown().forEach { file ->
// val filePath = file.absolutePath
// mClassPool.insertClassPath(filePath)
// if (shouldModify(filePath)) {
// val inputStream = FileInputStream(file)
// mTransformHelper.proceedModifyDir(filePath, inputStream)
// }
// }
// }
// }
//
// /**
// * 主要步骤:
// * 1.遍历所有jar文件
// * 2.解压jar然后遍历所有的class
// * 3.读取class的输入流并使用javassit修改然后保存到新的jar文件中
// */
// fun handleJar(jarFile: File): File {
// mClassPool.appendClassPath(jarFile.absolutePath)
// val inputJarFile = JarFile(jarFile)
// val entries = inputJarFile.entries()
// //创建一个新的文件
// val outputJarFile = File(jarFile.parentFile, "temp_" + jarFile.name)
// if (outputJarFile.exists()) outputJarFile.delete()
// val jarOutputStream = JarOutputStream(BufferedOutputStream(FileOutputStream(outputJarFile)))
// while (entries.hasMoreElements()) {
// val jarInputEntry = entries.nextElement()
// val jarInputEntryName = jarInputEntry.name
// var isIgnore = false
// for (i in mExcludePackages.indices){
// if (jarInputEntryName.contains(mExcludePackages[i])) {
// isIgnore = true
// break
// }
// }
// if (isIgnore) continue
// val outputJarEntry = JarEntry(jarInputEntryName)
// jarOutputStream.putNextEntry(outputJarEntry)
//
// val inputStream = inputJarFile.getInputStream(jarInputEntry)
// if (!shouldModify(jarInputEntryName)) {
// jarOutputStream.write(IOUtils.toByteArray(inputStream))
// inputStream.close()
// continue
// }
// mTransformHelper.proceedModifyJar(jarInputEntryName, jarOutputStream, inputStream)
// }
// inputJarFile.close()
// jarOutputStream.closeEntry()
// jarOutputStream.flush()
// jarOutputStream.close()
// return outputJarFile
// }
//
// private fun shouldModify(filePath: String): Boolean {
// return filePath.endsWith(".class")
// && !filePath.contains("R.class")
//// && !filePath.contains("$")
// && !filePath.contains("R$")
// && !filePath.contains("BuildConfig.class")
// }
//
//}

View File

@ -1,56 +0,0 @@
package com.gh.gamecenter.plugin
import com.gh.gamecenter.plugin.transform.Transformer
import org.apache.commons.io.IOUtils
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.util.jar.JarOutputStream
class GhTransformHelper {
private val transformers = ArrayList<Transformer>()
fun addTransformer(transformer: Transformer) {
transformers.add(transformer)
}
fun proceedModifyDir(filePath: String, inputStream: InputStream) {
transformers.forEach {
val ctClass = it.modifyClass(filePath, inputStream)
ctClass?.let {
ctClass.writeFile()
// 释放内存
ctClass.detach()
}
}
inputStream.close()
}
fun proceedModifyJar(filePath: String, jarOutputStream: JarOutputStream, iStream: InputStream) {
var byteCode: ByteArray? = null
var inputStream = iStream
transformers.forEach {
if (byteCode != null) {
inputStream = ByteArrayInputStream(byteCode)
}
val ctClass = it.modifyClass(filePath, inputStream)
ctClass?.let {
byteCode = ctClass.toBytecode()
// 释放内存
ctClass.detach()
}
}
if (byteCode == null) {
byteCode = IOUtils.toByteArray(inputStream)
}
jarOutputStream.write(byteCode!!)
jarOutputStream.flush()
inputStream.close()
}
}

View File

@ -0,0 +1,120 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.AdviceAdapter
abstract class MiniGameWebViewVisitorFactory :
AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor,
): ClassVisitor {
val targetClass = classContext.currentClassData.className.replace('.', '/')
return MiniGameWebViewVisitor(nextClassVisitor, targetClass)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.contains("QUAUtil")
}
}
class MiniGameWebViewVisitor(nextVisitor: ClassVisitor, private val targetClass: String) :
ClassVisitor(Opcodes.ASM9, nextVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?,
): MethodVisitor {
val originalMv = super.visitMethod(access, name, descriptor, signature, exceptions)
// Only modify the run() method
return if (name == "getSystemUA" && descriptor.equals("()Ljava/lang/String;")) {
MiniGameWebViewAdviceAdapter(
Opcodes.ASM9,
originalMv,
access,
name,
descriptor,
targetClass
)
} else {
originalMv
}
}
}
private class MiniGameWebViewAdviceAdapter(
api: Int,
mv: MethodVisitor,
access: Int,
name: String,
descriptor: String?,
private val targetClass: String,
) : AdviceAdapter(api, mv, access, name, descriptor) {
override fun onMethodEnter() {
val l0 = newLabel()
val l1 = newLabel()
// if (systemUA != null) {
mv.visitFieldInsn(Opcodes.GETSTATIC, targetClass, "systemUA", "Ljava/lang/String;")
mv.visitJumpInsn(Opcodes.IFNULL, l0)
// return systemUA;
mv.visitFieldInsn(Opcodes.GETSTATIC, targetClass, "systemUA", "Ljava/lang/String;")
mv.visitInsn(Opcodes.ARETURN)
mv.visitLabel(l0)
// String property = System.getProperty("http.agent");
mv.visitLdcInsn("http.agent")
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
"java/lang/System",
"getProperty",
"(Ljava/lang/String;)Ljava/lang/String;",
false
)
mv.visitVarInsn(Opcodes.ASTORE, 1) // Store the property in a local variable
// if (property == null) { return null; }
mv.visitVarInsn(Opcodes.ALOAD, 1)
mv.visitJumpInsn(Opcodes.IFNULL, l1)
// systemUA = java.net.URLEncoder.encode(property, "UTF-8");
mv.visitVarInsn(Opcodes.ALOAD, 1)
mv.visitLdcInsn("UTF-8")
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
"java/net/URLEncoder",
"encode",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
false
)
mv.visitFieldInsn(Opcodes.PUTSTATIC, targetClass, "systemUA", "Ljava/lang/String;")
// return systemUA;
mv.visitFieldInsn(Opcodes.GETSTATIC, targetClass, "systemUA", "Ljava/lang/String;")
mv.visitInsn(Opcodes.ARETURN)
mv.visitLabel(l1)
mv.visitInsn(Opcodes.ACONST_NULL)
mv.visitFieldInsn(Opcodes.PUTSTATIC, targetClass, "systemUA", "Ljava/lang/String;")
mv.visitInsn(Opcodes.ACONST_NULL)
mv.visitInsn(Opcodes.ARETURN)
}
}

View File

@ -0,0 +1,89 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
abstract class PluginAssetClassVisitorFactory:
AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor,
): ClassVisitor {
return PluginAssetClassVisitor(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return !classData.className.contains("PluginRedirectHelper")
&& !classData.className.contains("BuildConfig")
&& !classData.className.endsWith(".R")
}
}
class PluginAssetClassVisitor(nextVisitor: ClassVisitor) : ClassVisitor(Opcodes.ASM9, nextVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?,
): MethodVisitor {
val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
return AssetOpenMethodVisitor(mv)
}
class AssetOpenMethodVisitor(mv: MethodVisitor) : MethodVisitor(Opcodes.ASM9, mv) {
override fun visitMethodInsn(
opcode: Int, owner: String, name: String,
descriptor: String, isInterface: Boolean,
) {
// Print all method call in AssetManager
if ("android/content/res/AssetManager" == owner) {
println("owener:$owner method:$name opcode:$opcode desc:$descriptor")
}
// Replace AssetManager.open with com.gh.gamecenter.core.utils.PluginRedirectHelper.openAsset
if ("android/content/res/AssetManager" == owner
&& "open" == name
&& opcode == Opcodes.INVOKEVIRTUAL
&& "(Ljava/lang/String;)Ljava/io/InputStream;" == descriptor
) {
println("owener:$owner method:$name opcode:$opcode desc:$descriptor make it!")
return super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/gh/gamecenter/core/utils/PluginRedirectHelper",
"openAsset",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)Ljava/io/InputStream;",
isInterface
)
}
// Replace AssetManager.list with com.gh.gamecenter.core.utils.PluginRedirectHelper.listAsset
if ("android/content/res/AssetManager" == owner
&& "list" == name
&& opcode == Opcodes.INVOKEVIRTUAL
&& "(Ljava/lang/String;)[Ljava/lang/String;" == descriptor
) {
return super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/gh/gamecenter/core/utils/PluginRedirectHelper",
"listAsset",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;",
isInterface
)
}
return super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
}
}
}

View File

@ -1,201 +0,0 @@
package com.gh.gamecenter.plugin
import com.android.build.api.transform.Format
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformInvocation
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.io.FileUtils
import org.apache.commons.io.IOUtils
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
class PluginAssetTransform : Transform() {
override fun getName() = "PluginTransform"
override fun getInputTypes() = TransformManager.CONTENT_CLASS
override fun getScopes() = TransformManager.SCOPE_FULL_PROJECT
override fun isIncremental() = false
override fun transform(transformInvocation: TransformInvocation) {
if (!isIncremental) {
transformInvocation.outputProvider.deleteAll()
}
var index = 0
transformInvocation.inputs.forEach { input ->
// 处理 dir 部分
input.directoryInputs.forEach { directoryInput ->
val outputDir = transformInvocation.outputProvider
.getContentLocation(
directoryInput.name,
directoryInput.contentTypes,
directoryInput.scopes,
Format.DIRECTORY
)
FileUtils.copyDirectory(directoryInput.file, outputDir)
directoryInput.file.walkTopDown().forEach { file ->
if (file.isFile && file.extension == "class") {
val classReader = ClassReader(FileInputStream(file))
val classWriter = ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
val classVisitor = AssetOpenClassVisitor(classWriter)
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)
val fos = FileOutputStream(File(outputDir, file.relativeTo(directoryInput.file).path))
fos.write(classWriter.toByteArray())
fos.close()
}
}
}
// 处理 jar 部分
input.jarInputs.forEach { jarInput ->
val jarFile = jarInput.file
if (jarFile.exists() && jarFile.extension == "jar") {
val modifiedJarFile = modifyJar(jarFile)
// 必须给 jar 重新命名,否则会冲突
var jarName = jarFile.name
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length - 4)
}
val dest = transformInvocation.outputProvider?.getContentLocation(
jarName + "_" + index,
jarInput.contentTypes,
jarInput.scopes,
Format.JAR
)
FileUtils.copyFile(modifiedJarFile, dest)
index++
}
}
}
}
/**
* 主要步骤:
* 1.遍历所有jar文件
* 2.解压jar然后遍历所有的class
* 3.读取class的输入流并使用 ASM 修改,然后保存到新的 jar 文件中
*/
fun modifyJar(jarFile: File): File {
val jarInput = JarFile(jarFile)
val jarInputEntries = jarInput.entries()
// 创建一个新的文件
val jarOutput = File(jarFile.parentFile, "temp_" + jarFile.name)
if (jarOutput.exists()) jarOutput.delete()
val jarOutputStream = JarOutputStream(BufferedOutputStream(FileOutputStream(jarOutput)))
while (jarInputEntries.hasMoreElements()) {
val jarInputEntry = jarInputEntries.nextElement()
val jarInputEntryName = jarInputEntry.name
val jarInputStream = jarInput.getInputStream(jarInputEntry)
val zipEntry = ZipEntry(jarInputEntryName)
jarOutputStream.putNextEntry(zipEntry)
if (shouldModify(jarInputEntryName)) {
val classReader = ClassReader(IOUtils.toByteArray(jarInputStream))
val classWriter = ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
val classVisitor = AssetOpenClassVisitor(classWriter)
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)
jarOutputStream.write(classWriter.toByteArray())
} else {
jarOutputStream.write(IOUtils.toByteArray(jarInputStream))
}
jarOutputStream.closeEntry()
jarInputStream.close()
}
jarInput.close()
jarOutputStream.flush()
jarOutputStream.close()
return jarOutput
}
private fun shouldModify(filePath: String): Boolean {
return filePath.endsWith(".class")
&& !filePath.contains("PluginRedirectHelper.class")
&& !filePath.contains("R.class")
&& !filePath.contains("R$")
&& !filePath.contains("BuildConfig.class")
}
class AssetOpenClassVisitor(cv: ClassVisitor) : ClassVisitor(Opcodes.ASM9, cv) {
override fun visitMethod(
access: Int, name: String, descriptor: String,
signature: String?, exceptions: Array<String>?
): MethodVisitor {
val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
return AssetOpenMethodVisitor(mv)
}
}
class AssetOpenMethodVisitor(mv: MethodVisitor) : MethodVisitor(Opcodes.ASM9, mv) {
override fun visitMethodInsn(
opcode: Int, owner: String, name: String,
descriptor: String, isInterface: Boolean
) {
// Print all method call in AssetManager
if ("android/content/res/AssetManager" == owner) {
println("owener:$owner method:$name opcode:$opcode desc:$descriptor")
}
// Replace AssetManager.open with com.gh.gamecenter.core.utils.PluginRedirectHelper.openAsset
if ("android/content/res/AssetManager" == owner
&& "open" == name
&& opcode == Opcodes.INVOKEVIRTUAL
&& "(Ljava/lang/String;)Ljava/io/InputStream;" == descriptor) {
println("owener:$owner method:$name opcode:$opcode desc:$descriptor make it!")
return super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/gh/gamecenter/core/utils/PluginRedirectHelper",
"openAsset",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)Ljava/io/InputStream;",
isInterface
)
}
// Replace AssetManager.list with com.gh.gamecenter.core.utils.PluginRedirectHelper.listAsset
if ("android/content/res/AssetManager" == owner
&& "list" == name
&& opcode == Opcodes.INVOKEVIRTUAL
&& "(Ljava/lang/String;)[Ljava/lang/String;" == descriptor) {
return super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/gh/gamecenter/core/utils/PluginRedirectHelper",
"listAsset",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;",
isInterface)
}
return super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
}
}
}

View File

@ -0,0 +1,47 @@
package com.gh.gamecenter.plugin
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.AdviceAdapter
abstract class RoomClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor,
): ClassVisitor {
return RoomClassVisitor(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.contains("androidx.room.InvalidationTracker")
}
}
class RoomClassVisitor(nextVisitor: ClassVisitor) :
ClassVisitor(Opcodes.ASM9, nextVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?,
): MethodVisitor {
val originalMv = super.visitMethod(access, name, descriptor, signature, exceptions)
// Only modify the run() method
return if (name == "run" && descriptor == "()V") {
println("RoomClassVisitor found run method on $name")
TryCatchMethodVisitor(Opcodes.ASM9, originalMv, access, name, descriptor)
} else {
originalMv
}
}
}

View File

@ -0,0 +1,74 @@
package com.gh.gamecenter.plugin
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.AdviceAdapter
/**
* A [MethodVisitor] that adds a try-catch block around the original method's code.
* @param returnBoolean, if true, the catch block will return a default boolean value instead of void
*/
class TryCatchMethodVisitor(
api: Int,
mv: MethodVisitor,
access: Int,
name: String?,
descriptor: String?,
private val returnBoolean: Boolean = false,
) : AdviceAdapter(api, mv, access, name, descriptor) {
private val startLabel = org.objectweb.asm.Label()
private val endLabel = org.objectweb.asm.Label()
private val handlerLabel = org.objectweb.asm.Label()
override fun onMethodEnter() {
// Start of the try block
mv.visitLabel(startLabel)
}
override fun onMethodExit(opcode: Int) {
// End of try block. Only put it here if the opcode is not ATHROW
if (opcode != Opcodes.ATHROW) {
mv.visitLabel(endLabel)
}
}
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
// Exception handler (placed after the original method's code)
mv.visitLabel(handlerLabel)
// Store the exception in a local variable (slot 1)
mv.visitVarInsn(Opcodes.ASTORE, 1)
// Print the stack trace of the exception
mv.visitVarInsn(Opcodes.ALOAD, 1)
mv.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"java/lang/Throwable",
"printStackTrace",
"()V",
false
)
if (!returnBoolean) {
mv.visitInsn(Opcodes.RETURN)
} else {
mv.visitInsn(Opcodes.ICONST_0)
mv.visitInsn(Opcodes.IRETURN)
}
// Add the try-catch block to the method
// Catch all Throwable exceptions
mv.visitTryCatchBlock(
startLabel,
endLabel,
handlerLabel,
"java/lang/Throwable"
)
// Adjust maxStack and maxLocals. The exact values might need fine-tuning
// depending on the original method's complexity. We've added a few
// instructions, so we need to increase these values.
super.visitMaxs(maxStack + 2, maxLocals + 1)
}
}

View File

@ -118,14 +118,14 @@ ext {
sentry = "6.20.0"
autoServiceVersion = "1.0-rc7"
routerVersion = "1.2.2"
routerVersion = "1.2.4"
composeVersion = "1.2.1"
activityComposeVersion = "1.6.0"
composeCompilerVersion = "1.5.14"
constraintlayoutCompose = "1.0.1"
sensorsDataVersion = "6.8.0"
sensorsDataVersion = "6.8.4"
documentfile = "1.0.1"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.accelerator">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>

View File

@ -5,6 +5,8 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.csjad'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.csjad">
xmlns:tools="http://schemas.android.com/tools">
<!--必要权限-->
<uses-permission android:name="android.permission.INTERNET" />

View File

@ -5,6 +5,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.floatingwindow'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.floatingwindow">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
</application>

View File

@ -6,6 +6,8 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.jg.push'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.jg.push">
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.hihonor.push.sdk,com.heytap.mcssdk" />

View File

@ -3,6 +3,7 @@ apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "kotlin-kapt"
android {
namespace 'com.gh.gamecenter.selector'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.selector">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

View File

@ -9,6 +9,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.feedback'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.feedback">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.feedback">
xmlns:tools="http://schemas.android.com/tools">
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />

View File

@ -6,6 +6,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.oaid'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.oaid">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk tools:overrideLibrary="com.bun.miitmdid" />

View File

@ -9,6 +9,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.pkg'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.pkg">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
</application>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.pkg">
xmlns:tools="http://schemas.android.com/tools">
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />

View File

@ -5,6 +5,8 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.qqgame'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.qqgame">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application>

View File

@ -3,6 +3,7 @@ apply plugin: "org.jetbrains.kotlin.android"
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.sentry'
compileSdkVersion rootProject.ext.compileSdkVersion

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.sentry">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.wechat.pay">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>

View File

@ -13,7 +13,7 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Jul 19 10:16:09 CST 2017
org.gradle.jvmargs=-Xmx4096m -XX\:MaxPermSize\=2048m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
org.gradle.jvmargs=-Xmx4096m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
#开启gradle并行编译
org.gradle.parallel=true
#开启守护进程
@ -96,4 +96,8 @@ android.injected.testOnly = false
# 动态配置插件
isRelease = true
pluginBasePath=vasdk/
pluginBasePath=vasdk/
android.defaults.buildfeatures.buildconfig=true
android.enableBuildConfigAsBytecode=true
android.nonFinalResIds=false
android.defaults.buildfeatures.renderscript=true

View File

@ -1,6 +1,6 @@
#Mon Oct 30 17:29:06 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.2-bin.zip
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,7 +1,6 @@
allprojects { project ->
buildscript {
ext.booster_version = '4.9.0'
ext.plugin_version = "0.3.0"
ext.booster_version = '5.0.0'
repositories {
mavenLocal()
@ -9,16 +8,10 @@ allprojects { project ->
mavenCentral()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public' }
maven { url "https://artifact.bytedance.com/repository/byteX/" }
maven { url 'https://maven.aliyun.com/repository/public' }
}
dependencies {
// byteX
classpath "com.bytedance.android.byteX:base-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:const-inline-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:method-call-opt-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:field-assign-opt-plugin:${plugin_version}"
// booster
classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
@ -45,62 +38,6 @@ allprojects { project ->
project.apply plugin: 'com.didiglobal.booster'
project.apply plugin: "com.gh.gamecenter.plugin"
project.apply plugin: 'bytex'
project.apply plugin: 'bytex.method_call_opt' // 移除 log https://github.com/bytedance/ByteX/blob/master/method-call-opt-plugin/README-zh.md
project.apply plugin: 'bytex.field_assign_opt' //去除重复的赋值 https://github.com/bytedance/ByteX/blob/master/field-assign-opt-plugin/README-zh.md
//
project.method_call_opt {
enable true
enableInDebug false
logLevel "DEBUG"
//是否在log中显示删除方法调用指令后的方法指令一般调试时使用
showAfterOptInsLog false
//需要删除的方法配置
methodList = [
//下面的每一项配置必须严格按照数据配置,一个地方不对这一项不生效。
//class#method#desc
"android/util/Log#v#(Ljava/lang/String;Ljava/lang/String;)I",
"android/util/Log#v#(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I",
"android/util/Log#d#(Ljava/lang/String;Ljava/lang/String;)I",
"android/util/Log#d#(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I",
"android/util/Log#i#(Ljava/lang/String;Ljava/lang/String;)I",
"android/util/Log#i#(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I",
"android/util/Log#w#(Ljava/lang/String;Ljava/lang/String;)I",
"android/util/Log#w#(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I",
"android/util/Log#e#(Ljava/lang/String;Ljava/lang/String;)I",
"android/util/Log#e#(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I",
"android/util/Log#println#(ILjava/lang/String;Ljava/lang/String;)I",
"java/lang/Throwable#printStackTrace#()V",
"com/google/devtools/build/android/desugar/runtime/ThrowableExtension#printStackTrace#(Ljava/lang/Throwable;)V",
//项目中的方法
"com/lightgame/utils/Utils#log#(Ljava/lang/String;)V",
"com/lightgame/utils/Utils#log#(Ljava/lang/int;Ljava/lang/String;Ljava/lang/String;)V",
"com/lightgame/utils/Utils#log#(Ljava/lang/String;Ljava/lang/String;)V",
"com/lightgame/utils/Utils#log#(Ljava/lang/String;Ljava/lang/Object;)V",
"com/lightgame/utils/Utils#log#(Ljava/lang/Object;)V",
"com/gh/gamecenter/common/util/MtaHelper#onEvent#(Ljava/lang/Object;Ljava/lang/String;)V",
"com/gh/gamecenter/common/util/MtaHelper#onEventWithTime#(Ljava/lang/String;I[Ljava/lang/String;)V",
"com/gh/gamecenter/common/util/MtaHelper#onEventWithBasicDeviceInfo#(Ljava/lang/String;[Ljava/lang/String;)V"
]
onlyCheckList = []
whiteList = [
"com/tencent/qqmini/minigame/opensdk/share/OpenSdkShareHelper*",
]
}
project.field_assign_opt {
enable false
enableInDebug false
logLevel "INFO"
removeLineNumber true // 同时移除赋值对应的行号信息(如果有的话),默认true。
whiteList = [
//白名单ClassName.FieldName 。不支持模式匹配
//"android.support.constraint.solver.ArrayRow.isSimpleDefinition"
]
}
}
}

View File

@ -1,7 +1,6 @@
allprojects { project ->
buildscript {
ext.booster_version = '4.9.0'
ext.plugin_version = "0.3.0"
ext.booster_version = '5.0.0'
repositories {
mavenLocal()
@ -14,12 +13,6 @@ allprojects { project ->
}
dependencies {
// byteX
classpath "com.bytedance.android.byteX:base-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:const-inline-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:method-call-opt-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:field-assign-opt-plugin:${plugin_version}"
// booster
classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
// classpath "com.didiglobal.booster:booster-transform-shared-preferences:$booster_version"
@ -35,7 +28,6 @@ allprojects { project ->
mavenCentral()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public' }
maven { url "https://artifact.bytedance.com/repository/byteX/" }
maven { url 'https://maven.aliyun.com/repository/public' }
}
@ -45,20 +37,6 @@ allprojects { project ->
project.apply plugin: 'com.didiglobal.booster'
project.apply plugin: "com.gh.gamecenter.plugin"
project.apply plugin: 'bytex'
project.apply plugin: 'bytex.field_assign_opt' //去除重复的赋值 https://github.com/bytedance/ByteX/blob/master/field-assign-opt-plugin/README-zh.md
project.field_assign_opt {
enable false
enableInDebug false
logLevel "INFO"
removeLineNumber true // 同时移除赋值对应的行号信息(如果有的话),默认true。
whiteList = [
//白名单ClassName.FieldName 。不支持模式匹配
//"android.support.constraint.solver.ArrayRow.isSimpleDefinition"
]
}
}
}

View File

@ -20,6 +20,8 @@ android {
lintOptions {
abortOnError false
}
namespace "com.zhihu.matisse"
}
dependencies {

View File

@ -13,8 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.zhihu.matisse" >
<manifest xmlns:android = "http://schemas.android.com/apk/res/android">
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" />

View File

@ -9,4 +9,6 @@ android {
defaultConfig {
consumerProguardFiles 'proguard-library.txt'
}
namespace "com.gh.qqshare"
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.gh.qqshare" >
<manifest xmlns:android = "http://schemas.android.com/apk/res/android">
<uses-permission android:name = "android.permission.INTERNET" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />

View File

@ -7,6 +7,7 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.common'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.common">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 允许应用程序获取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@ -6,6 +6,7 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.core'
compileSdkVersion rootProject.ext.compileSdkVersion

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.core">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -7,6 +7,7 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.feature'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.feature">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -4,6 +4,7 @@ plugins {
}
android {
namespace 'com.gh.vspace.installexternalgames'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.vspace.installexternalgames">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

View File

@ -7,6 +7,7 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.login'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.login">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="com.tencent.mm" />

View File

@ -9,6 +9,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.message'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.message">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.message">
xmlns:tools="http://schemas.android.com/tools">
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />

View File

@ -2,11 +2,11 @@ plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'com.sensorsdata.analytics.android'
id 'com.google.devtools.ksp'
}
android {
namespace 'com.gh.gamecenter.sensorsdata'
compileSdk rootProject.ext.compileSdkVersion
defaultConfig {
@ -87,14 +87,6 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
sensorsAnalytics {
sdk {
disableIMEI = true
disableCarrier = true
disableMacAddress = true
}
}
kotlinOptions {
jvmTarget = '1.8'
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.sensorsdata">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

View File

@ -9,6 +9,7 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android {
namespace 'com.gh.gamecenter.setting'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.setting">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.setting">
xmlns:tools="http://schemas.android.com/tools">
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />

View File

@ -5,6 +5,7 @@ plugins {
}
android {
namespace 'com.gh.gamecenter.va.api'
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter.va.api">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -22,6 +22,8 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion
namespace 'com.gh.gamecenter.va.impl'
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter.va.impl">
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.lg.vspace" />

View File

@ -81,6 +81,7 @@ def optionalVaModules = [
'va-feature-realname': 'vasdk/feature/realname-window',
'va-library-commons' : 'vasdk/commons',
'va-library-network' : 'vasdk/library/network',
'va-feature-translate' : 'vasdk/feature/translate',
'va-archive' : 'vasdk/archive',
'va-plugin-constant' : 'vasdk/plugin/constant',
'va-plugin-host' : 'vasdk/host',

2
vasdk

Submodule vasdk updated: 932474708c...51793ea93c