Skip to content

Commit

Permalink
feat: giokit 集成在SDK 插件中 (#20)
Browse files Browse the repository at this point in the history
* add giokit extension in sdk plugin

* update plugin version to 4.0.0

* update snapshot publishToMavenLocal

* fix publishToMavenLocal

* fix giokit-no-op

* update readme

* fix test gradle version

* v3.5.2 (#21)

* Fix/warn (#22)

* v3.5.2

* now log.warn control by LOG_ENABLED

* saas plugin params include enableRn

* add giokit extension in sdk plugin

* update plugin version to 4.0.0

* update snapshot publishToMavenLocal

* fix publishToMavenLocal

* fix giokit-no-op

* update readme

* fix test gradle version

* autotrackerParams include extension.adapter & inject.

* giokit plugin: okhttp inject method desc changed

* giokit plugin: add GioCode to source/main/java
  • Loading branch information
cpacm authored Dec 26, 2023
1 parent 5e0b842 commit 10d8e6c
Show file tree
Hide file tree
Showing 50 changed files with 1,554 additions and 245 deletions.
71 changes: 44 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,13 @@

该项目为 [growingio-sdk-android-autotracker](https://github.com/growingio/growingio-sdk-android-autotracker/) 的插件部分,主要用于实现无埋点的代码插入功能。

项目主要模块为二个部分:

1. autotracker-gradle-plugin 插件代码实现部分,主要功能为:
* 适配 AGP 8.0 Instrumentation API;
* 兼容 AGP4.2及其更早版本的 Transform API;
* 优化插件对脱糖的处理;
* 兼容 AGP 7.0 及其以上 `pluginManagement` 的依赖方式;
* 提供了完整的单元测试。

2. inject-annotation 无埋点代码Hook注解及其处理器, 用于生成无埋点Hook配置类以便插件进行无埋点代码插入
* 提供两种注解方式,一是指向对应的类二是自己填入需要注解的类的描述符;
* 使用 KSP kotlin 注解处理器生成 kotlin 代码,比传统的APT和KAPT效率更高;
* inject-descriptor 为注解的描述文件,全部由接口文件组成;
Growingio Sdk Gradle Plugin 4.0 具有以下的功能特性:
* 适配 AGP 8.0 Instrumentation API;
* 兼容 AGP4.2及其更早版本的 Transform API;
* 在插件中可以配置集成Giokit;

## 如何集成
这里只说明在 Android Gradle插件为7.0及以上版本时的集成方式,若是AGP7以下则按照 [插件集成](https://growingio.github.io/growingio-sdk-docs/docs/android/base/Introduce#添加插件) 集成即可
这里只说明在 Android Gradle插件为7.0及以上版本时的集成方式

### 添加 Maven 仓库
需要在 project 中的 `settings.gradle` 文件中添加Maven仓库
Expand All @@ -29,10 +20,9 @@
pluginManagement {
repositories {
// 添加maven仓库
mavenCentral()
gradlePluginPortal()
//如果使用 SNAPSHOT 版本,则需要使用如下该仓库。
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" }
gradlePluginPortal()
google()
}
Expand All @@ -58,7 +48,7 @@ plugins {
···
// 添加GrowingIO 无埋点 SDK 插件
id 'com.growingio.android.autotracker' version '3.4.0' apply false
id 'com.growingio.android.autotracker' version '4.0.0' apply false
}
```

Expand All @@ -71,6 +61,7 @@ plugins {
// 使用 GrowingIO 无埋点 SDK 插件
id 'com.growingio.android.autotracker'
}
```

## 插件配置说明
Expand All @@ -79,13 +70,11 @@ plugins {

| Extension | 参数类型 | 是否必填 | 默认值 | 说明 | 版本 |
| :------------------------- | :------ | :----: |:------ |:------| -------------------------- |
| `logEnabled` | `Boolean` || `false` | 编译时是否输出log日志 | |
| `includePackages` | `Array<String>` || `null` | 需要额外包含编译的包名 | |
| `excludePackages` | `Array<String>` || `null` | 需要跳过编译的包名 | |
| `analyticsAdapter` | `Extension` || - | 用于配置是否适配第三方分析数据 | |
| - `firebaseAnalytics` | `Boolean` || `false` | 用于配置是否适配Firebase分析SDK | |
| - `googleAnalytics` | `Boolean` || `false` | 用于配置是否适配GoogleAnalyticsSDK | |

| logEnabled | _Boolean_ || `false` | 编译时是否输出log日志 | |
| skipDependencyCheck | _Boolean_ || `false` | 编译时检测当前project是否配置SDK依赖(模块中依赖时配置为true) | |
| includePackages | _Array<String\>_ || `null` | 需要额外包含编译的包名 | |
| excludePackages | _Array<String\>_ || `null` | 需要跳过编译的包名 | |
| giokit | _GiokitExtension_ || `null` | 可以用来配置是否引入 Giokit | |

配置代码示例
```groony
Expand All @@ -99,9 +88,8 @@ growingAutotracker {
logEnabled false
includePackages "com.growingio.xxx1","com.growingio.xxx2"
excludePackages "com.cpacm.xxx1"
analyticsAdapter {
firebaseAnalytics = false
googleAnalytics = false
giokit {
//...
}
}
Expand All @@ -111,6 +99,35 @@ dependencies {
}
```

### Giokit 配置

| Extension | 参数类型 | 是否必填 | 默认值 | 说明 |
| :------------------------- | :------ | :----: |:------ |:------|
| enabled | _Boolean_ || `false` | 是否添加 Giokit |
| trackerFinderEnabled | _Boolean_ || `true` | 查找App下调用App埋点接口的信息 |
| trackerFinderDomain | _Array<String\>_ || 默认为应用 ApplicationId | 查找的范围 |
| trackerCalledMethod | _Array<String\>_ || 默认为SDK相应接口 | 要查找的类和方法 |
| autoAttachEnabled | _Boolean_ || `true` | GioKit 是否自动依附在Activity上,若设为false,需要自行调用api打开GioKit |
| releaseEnabled | _Boolean_ || `false` | **请不要打开**,否则会在 Release 打包中包含 GioKit 代码 |
| autoInstallVersion | _String_ || `2.0.0` | 自动依赖的GioKit版本号 |

现在SDK不用再额外引入 Giokit,只需要在插件中开启即可。示例如下:

```groovy
growingAutotracker {
logEnabled true
giokit {
enabled false //开启则会引入 GioKit
trackerFinderEnabled true
trackerFinderDomain "com.xxxx.yourapplication"
trackerCalledMethod "com.growingio.android.tracker#trackCumtomEvent"
autoAttachEnabled true
releaseEnabled false
autoInstallVersion "2.0.0"
}
}
```


## License
```
Expand Down
10 changes: 7 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ plugins {
}

android {
compileSdk 31
compileSdk 33

defaultConfig {
applicationId "com.growingio.android.plugin"
minSdk 21
targetSdk 31
targetSdk 33
versionCode 1
versionName "1.0"

Expand Down Expand Up @@ -40,6 +40,10 @@ growingAutotracker {
firebaseAnalytics false
googleAnalytics false
}
giokit {
enabled true
autoInstallVersion "2.0.0-SNAPSHOT"
}
}


Expand All @@ -50,7 +54,7 @@ dependencies {
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

implementation 'com.growingio.android:autotracker-cdp:3.5.0'
implementation 'com.growingio.android:autotracker:4.0.0-SNAPSHOT'

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import com.growingio.android.sdk.autotrack.GrowingAutotracker

class MainActivity : AppCompatActivity() {
private val mAllFragments = arrayListOf<Fragment>()
Expand All @@ -28,6 +29,8 @@ class MainActivity : AppCompatActivity() {
tttt.setOnClickListener {
tttt.visibility = if (tttt.isVisible == true) View.GONE else View.VISIBLE
}

GrowingAutotracker.get().autotrackPage(this, javaClass.simpleName)
}

private fun setFragment(index: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

import androidx.annotation.RequiresApi;

import com.growingio.android.sdk.autotrack.CdpAutotrackConfiguration;
import com.growingio.android.sdk.autotrack.AutotrackConfiguration;
import com.growingio.android.sdk.autotrack.GrowingAutotracker;
import com.growingio.android.sdk.track.log.Logger;

Expand All @@ -36,7 +36,7 @@
public class PluginApplication extends Application {
private static final String TAG = "PluginApplication";

private static CdpAutotrackConfiguration sConfiguration;
private static AutotrackConfiguration sConfiguration;

@RequiresApi(api = Build.VERSION_CODES.O_MR1)
@Override
Expand All @@ -45,7 +45,7 @@ public void onCreate() {
super.onCreate();

if (sConfiguration == null) {
sConfiguration = new CdpAutotrackConfiguration("ac04dfef4a1b6ec7", "growing.6b963145e9509ad0")
sConfiguration = new AutotrackConfiguration("ac04dfef4a1b6ec7", "growing.6b963145e9509ad0")
.setDataSourceId("ae1a372733eabfa8")
.setDataCollectionServerHost("https://collector-opdemo.growingio.com")
.setDebugEnabled(true)
Expand All @@ -55,9 +55,7 @@ public void onCreate() {

enableStrictMode();

long startTime = System.currentTimeMillis();
GrowingAutotracker.startWithConfiguration(this, sConfiguration);
Log.d(TAG, "start time: " + (System.currentTimeMillis() - startTime));
}

private boolean isMainProcess() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import java.util.concurrent.TimeUnit
* Transform agent
* @author cpacm 2022.4.1
*/
@Suppress("DEPRECATION")
internal class GrowingClassRewriter(
private val delegate: TransformInvocation,
internal val transform: GrowingBaseTransform,
Expand All @@ -56,6 +55,8 @@ internal class GrowingClassRewriter(

override val isDebuggable = getVariant(project)?.buildType?.isDebuggable ?: false

override val gioScheme: String by lazy { getGioScheme(project) }

override fun hasProperty(name: String) = project.hasProperty(name)

override fun <T> getProperty(name: String, default: T): T = project.getProperty(name, default)
Expand Down Expand Up @@ -129,6 +130,7 @@ internal class GrowingClassRewriter(
)
}
}

else -> {}
}
}
Expand All @@ -152,6 +154,7 @@ internal class GrowingClassRewriter(
}
file.delete()
}

Status.ADDED, Status.CHANGED -> {
info("Transforming $file")
outputProvider?.let { provider ->
Expand All @@ -167,6 +170,7 @@ internal class GrowingClassRewriter(
}
}
}

else -> {}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ interface AutoTrackerContext {
*/
val isDebuggable: Boolean

/**
* The data with growing.xxxxxx in intent-filter
*/
val gioScheme: String

/**
* Check if has the specified property. Generally, the property is equivalent to project property
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import com.android.build.gradle.AppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.BaseVariant
import com.growingio.android.plugin.util.AndroidManifestHandler
import com.growingio.android.plugin.util.e
import com.growingio.android.plugin.util.g
import org.apache.commons.compress.archivers.jar.JarArchiveEntry
import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
Expand All @@ -23,6 +25,7 @@ import java.util.concurrent.TimeUnit
import java.util.jar.JarFile
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import javax.xml.parsers.SAXParserFactory

inline fun <reified T : BaseExtension> Project.getAndroid(): T = extensions.getByName("android") as T

Expand Down Expand Up @@ -56,26 +59,33 @@ fun TransformInvocation.getVariant(project: Project): BaseVariant? {
variant = it
}
}

is LibraryExtension -> {
androidExtension.libraryVariants.all { variant = it }
}
}
return variant
}

// return project.getAndroid<BaseExtension>().let { android ->
// this.context.variantName.let { variant ->
// when (android) {
// is AppExtension -> when {
// variant.endsWith("AndroidTest") -> android.testVariants.single { it.name == variant }
// variant.endsWith("UnitTest") -> android.unitTestVariants.single { it.name == variant }
// else -> android.applicationVariants.single { it.name == variant }
// }
// is LibraryExtension -> android.libraryVariants.single { it.name == variant }
// else -> error("variant not found")
// }
//
// }
// }
fun getGioScheme(project: Project): String {
var urlScheme = ""
val appExtension = project.extensions.getByName("android") as? AppExtension
appExtension?.let {
val manifest = it.sourceSets.getAt("main").manifest.srcFile
// 获取 AndroidManifest 下配置的 url scheme 如"growing.d80871b41ef40518"
// 执行clean之后,无法再在 build 文件中找到 build/intermediates/merged_manifest/debug/AndroidManifest.xml,故无法找到 urlscheme
// 第二次build时将会找到。。
// 同样,如果只改变xml值未改变代码由于无法触发插件也不能实时更新
manifest.let {
val parser = SAXParserFactory.newInstance().newSAXParser()
val handler = AndroidManifestHandler()
parser.parse(manifest, handler)
urlScheme = handler.growingioScheme ?: ""
g("growingio scheme is ${urlScheme}")
g("app package is ${handler.appPackageName}")
}
}
return urlScheme
}

fun TransformInvocation.getBootClasspath(project: Project): Collection<File> {
Expand Down Expand Up @@ -107,15 +117,19 @@ fun File.transform(output: File, transformer: (ByteArray) -> ByteArray = { it ->
it.transform(File(output, base.relativize(it.toURI()).path), transformer)
}
}

isFile -> when (extension.toLowerCase(Locale.getDefault())) {
"jar" -> JarFile(this).use {
it.transform(output, transformer)
}

"class" -> this.inputStream().use {
it.transform(transformer).redirect(output)
}

else -> this.copyTo(output, true)
}

else -> throw IOException("Unexpected file: ${this.canonicalPath}")
}
}
Expand Down Expand Up @@ -155,6 +169,7 @@ fun ZipFile.transform(
getInputStream(entry)
}
}

else -> getInputStream(entry)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ class AndroidComponentsExtensionCompatApi42Impl(
private val project: Project
) : AndroidComponentsExtensionCompat {

override fun onAllVariants(block: (ComponentCompat) -> Unit) {
override fun onAllVariants(block: (ComponentCompat) -> Unit, testBlock: (ComponentCompat) -> Unit) {
val actual = project.extensions.getByType(AndroidComponentsExtension::class.java)
val allSelectors = actual.selector().all()
val wrapFunction: (Component) -> Unit = { block.invoke(ComponentCompatApi42Impl(it)) }
val testWrapFunction: (Component) -> Unit = { testBlock.invoke(ComponentCompatApi42Impl(it)) }
actual.onVariants(allSelectors, wrapFunction)
actual.androidTests(allSelectors, wrapFunction)
actual.unitTests(allSelectors, wrapFunction)
actual.androidTests(allSelectors, testWrapFunction)
actual.unitTests(allSelectors, testWrapFunction)
}
}
Loading

0 comments on commit 10d8e6c

Please sign in to comment.