Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: abtest #220

Merged
merged 7 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/pre_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,8 @@ jobs:
with:
api-level: 31
target: default
ram-size: 4096M
arch: x86_64
disable-animations: true
disk-size: 6000M
heap-size: 600M
working-directory: ./demo
script: ./gradlew :app:connectedAndroidTest --stacktrace

Expand Down
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ subprojects {
kotlin {
target '**/*.kt'
targetExclude("$buildDir/**/*.kt")

ktlint()
ktlint().editorConfigOverride([
"ktlint_standard_comment-wrapping": "disabled",
"max_line_length" : 2147483647,
])
}
groovyGradle {
target '*.gradle'
Expand Down
14 changes: 7 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
[versions]
compileSdk = "33"
compileSdk = "34"
minSdk = "17"

# https://developer.android.google.cn/jetpack/androidx/explorer?hl=en&case=all
androidxlifecycle = "2.6.1"
androidxlifecycle = "2.8.2"
androidxtest = "1.5.0"
navigation = "2.5.3"

pluginGradle = "7.4.2" # 4.2.2-7.4.2
kotlin = "1.9.21"
kotlin = "2.0.0"

spotless = "6.20.0"
spotless = "6.25.0"

# https://developer.android.com/jetpack/androidx/releases/compose-compiler
# composeBom = "2023.04.00"

# https://github.com/Kotlin/kotlinx.coroutines
coroutines = "1.6.4"
coroutines = "1.8.1"
# https://github.com/pinterest/ktlint
ktlint = "0.48.2"
# https://square.github.io/okhttp/changelogs/changelog_4x/
Expand All @@ -30,8 +30,8 @@ protobuf = "3.22.3"
powermock = "2.0.9"

# !!! SDK VERSION !!!
growingio = "4.3.1"
growingioCode = "40301"
growingio = "4.3.3-SNAPSHOT"
growingioCode = "40303"
growingioPlugin = "4.3.0"
junit = "1.1.5"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ private void sendAbTestTrackEvent(ABExperiment abExperiment) {
attributesBuilder
.addAttribute("$exp_id", abExperiment.getExperimentId())
.addAttribute("$exp_strategy_id", abExperiment.getStrategyId())
.addAttribute("$exp_layer_id", abExperiment.getLayerId());
.addAttribute("$exp_layer_id", abExperiment.getLayerId())
.addAttribute("$exp_layer_name", abExperiment.getExpLayerName())
.addAttribute("$exp_name", abExperiment.getExpName())
.addAttribute("$exp_strategy_name", abExperiment.getExpStrategyName());
CustomEvent.Builder customEventBuilder = new CustomEvent.Builder();
customEventBuilder.setEventName("$exp_hit");
customEventBuilder.setAttributes(attributesBuilder.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
import java.util.Map;

class ABTestResponse {

private static final String LAYER_ID = "layerId";
private static final String LAYER_NAME = "layerName";
private static final String STRATEGY_ID = "strategyId";
private static final String STRATEGY_NAME = "strategyName";
private static final String EXPERIMENT_ID = "experimentId";
private static final String EXPERIMENT_NAME = "experimentName";
private static final String VARIABLES = "variables";

private int code = -1;
private String errorMsg;

Expand All @@ -48,9 +57,9 @@ public static ABTestResponse parseHttpJson(long expiredTime, String layerId, Str
int code = jsonObject.getInt("code");
response.code = code;
if (code == 0) {
long experimentId = jsonObject.optLong("experimentId");
long strategyId = jsonObject.optLong("strategyId");
JSONObject variables = jsonObject.optJSONObject("variables");
long experimentId = jsonObject.optLong(EXPERIMENT_ID);
long strategyId = jsonObject.optLong(STRATEGY_ID);
JSONObject variables = jsonObject.optJSONObject(VARIABLES);
Map<String, String> variableMap = new HashMap<>();
if (variables != null) {
Iterator<String> keys = variables.keys();
Expand All @@ -62,6 +71,10 @@ public static ABTestResponse parseHttpJson(long expiredTime, String layerId, Str
response.expiredTime = System.currentTimeMillis() + expiredTime;
response.naturalDaytime = tomorrowMill();
response.abExperiment = new ABExperiment(layerId, strategyId, experimentId, variableMap);
String expLayerName = jsonObject.optString(LAYER_NAME);
String expName = jsonObject.optString(EXPERIMENT_NAME);
String expStrategyName = jsonObject.optString(STRATEGY_NAME);
response.abExperiment.setExperimentNames(expLayerName, expName, expStrategyName);
} else {
response.errorMsg = jsonObject.getString("errorMsg");
}
Expand Down Expand Up @@ -104,17 +117,20 @@ public String toSavedJson() {
jsonObject.put("expiredTime", expiredTime);
jsonObject.put("naturalDaytime", naturalDaytime);
if (abExperiment != null) {
jsonObject.put("layerId", abExperiment.getLayerId());
jsonObject.put("strategyId", abExperiment.getStrategyId());
jsonObject.put("experimentId", abExperiment.getExperimentId());
jsonObject.put(LAYER_ID, abExperiment.getLayerId());
jsonObject.put(STRATEGY_ID, abExperiment.getStrategyId());
jsonObject.put(EXPERIMENT_ID, abExperiment.getExperimentId());
Map<String, String> variableMap = abExperiment.getVariables();
Iterator<String> keys = variableMap.keySet().iterator();
JSONObject variablesJson = new JSONObject();
while (keys.hasNext()) {
String key = keys.next();
variablesJson.put(key, variableMap.get(key));
}
jsonObject.put("variables", variablesJson);
jsonObject.put(VARIABLES, variablesJson);
jsonObject.put(LAYER_NAME, abExperiment.getExpLayerName());
jsonObject.put(EXPERIMENT_NAME, abExperiment.getExpName());
jsonObject.put(STRATEGY_NAME, abExperiment.getExpStrategyName());
}

return jsonObject.toString();
Expand All @@ -133,17 +149,21 @@ public static ABTestResponse parseSavedJson(String json) {
abTestResponse.expiredTime = expiredTime;
abTestResponse.naturalDaytime = naturalDaytime;

String layerId = jsonObject.getString("layerId");
long strategyId = jsonObject.getLong("strategyId");
long experimentId = jsonObject.getLong("experimentId");
JSONObject variables = jsonObject.getJSONObject("variables");
String layerId = jsonObject.getString(LAYER_ID);
long strategyId = jsonObject.getLong(STRATEGY_ID);
long experimentId = jsonObject.getLong(EXPERIMENT_ID);
JSONObject variables = jsonObject.getJSONObject(VARIABLES);
Iterator<String> keys = variables.keys();
Map<String, String> variableMap = new HashMap<>();
while (keys.hasNext()) {
String key = keys.next();
variableMap.put(key, variables.get(key).toString());
}
abTestResponse.abExperiment = new ABExperiment(layerId, strategyId, experimentId, variableMap);
String expLayerName = jsonObject.optString(LAYER_NAME);
String expName = jsonObject.optString(EXPERIMENT_NAME);
String expStrategyName = jsonObject.optString(STRATEGY_NAME);
abTestResponse.abExperiment.setExperimentNames(expLayerName, expName, expStrategyName);
return abTestResponse;
} catch (JSONException e) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ internal class JsonFactoryGenerator(
ClassName.get(
ProcessUtils.JSON_SERIALIZABLE_PACKAGE,
ProcessUtils.JSON_SERIALIZABLE_CLASS,
), // rawType
ClassName.get(eventType), // the value for T
builderType, // the value for R
),
ClassName.get(eventType),
builderType,
)

val jonSerialBuilder = TypeSpec.classBuilder(generateClass).addJavadoc(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ internal class JsonSerializerGenerator(
val builderType = ClassName.get(eventBuilderType)

val superinterface = ParameterizedTypeName.get(
ClassName.get(JSON_SERIALIZABLE_PACKAGE, JSON_SERIALIZABLE_CLASS), // rawType
ClassName.get(eventType), // the value for T
builderType, // the value for R
ClassName.get(JSON_SERIALIZABLE_PACKAGE, JSON_SERIALIZABLE_CLASS),
ClassName.get(eventType),
builderType,
)

val jonSerialBuilder = TypeSpec.classBuilder(generateClass).addJavadoc(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.growingio.android.sdk.track.log.Logger;
import com.growingio.android.sdk.track.providers.ActivityStateProvider;
import com.growingio.android.sdk.track.providers.ConfigurationProvider;
import com.growingio.android.sdk.track.providers.EventBuilderProvider;
import com.growingio.android.sdk.track.providers.TrackerLifecycleProvider;
import com.growingio.android.sdk.track.utils.ActivityUtil;

Expand Down Expand Up @@ -60,6 +61,7 @@ private static class SingleInstance {
private static final PageProvider INSTANCE = new PageProvider();
}

private EventBuilderProvider eventBuilderProvider;
private ActivityStateProvider activityStateProvider;
private PageConfig pageConfig;

Expand All @@ -71,6 +73,7 @@ private PageProvider() {
@Override
public void setup(TrackerContext context) {
activityStateProvider = context.getActivityStateProvider();
eventBuilderProvider = context.getEventBuilderProvider();

ConfigurationProvider configurationProvider = context.getConfigurationProvider();
AutotrackConfig autotrackConfig = configurationProvider.getConfiguration(AutotrackConfig.class);
Expand Down Expand Up @@ -229,6 +232,12 @@ private void sendPage(Page<?> page) {
}

private void generatePageEvent(Page<?> page) {
Page<?> activePage = page.lastActivePage();
if (activePage != null) {
eventBuilderProvider.setCustomEventReferPage(activePage.path(), activePage.getShowTimestamp());
} else {
eventBuilderProvider.setCustomEventReferPage("/", 0);
}
String orientation = TrackMainThread.trackMain().getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
? PageEvent.ORIENTATION_PORTRAIT : PageEvent.ORIENTATION_LANDSCAPE;
TrackMainThread.trackMain().postEventToTrackMain(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ public void setup() {
Application application = ApplicationProvider.getApplicationContext();

Map<Class<? extends Configurable>, Configurable> modules = new HashMap<>();
modules.put(AutotrackConfig.class, new AutotrackConfig().setImpressionScale(0.5f));
modules.put(AutotrackConfig.class,
new AutotrackConfig().setImpressionScale(0.5f)
.setWebViewBridgeEnabled(true)
.setPageRuleXml(0)
.addPageRule("MainActivity", "com.growingio.android.sdk.autotrack.RobolectricActivity")
.addPageMatchRule(".*")
.enableFragmentTag(false)

);
TrackerLifecycleProviderFactory.create().createConfigurationProviderWithConfig(new CoreConfiguration("AutotrackTest", "growingio://autotrack"), modules);
autotracker = new Autotracker(application);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ private static EventV3Protocol.EventV3Dto protocol(GEvent gEvent) {
if (gEvent instanceof PageLevelCustomEvent) {
PageLevelCustomEvent plEvent = (PageLevelCustomEvent) gEvent;
eventBuilder.setPath(plEvent.getPath()); //10
eventBuilder.setPageShowTimestamp(plEvent.getPageShowTimestamp()); //23
if (plEvent.getPageShowTimestamp() > 0) {
eventBuilder.setPageShowTimestamp(plEvent.getPageShowTimestamp());//23
}
}
if (gEvent instanceof VisitEvent) {
VisitEvent visitEvent = (VisitEvent) gEvent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,20 @@ public class HybridBridgeProvider extends ListenerContainer<OnDomChangedListener
HybridBridgeProvider() {
}


private ConfigurationProvider configurationProvider;
private AppInfoProvider appInfoProvider;
private UserInfoProvider userInfoProvider;
private boolean autoJsSdkInject = false;

@Override
public void setup(TrackerContext context) {
configurationProvider = context.getConfigurationProvider();
appInfoProvider = context.getProvider(AppInfoProvider.class);
userInfoProvider = context.getUserInfoProvider();
HybridConfig hybridConfig = configurationProvider.getConfiguration(HybridConfig.class);
if (hybridConfig != null) {
autoJsSdkInject = hybridConfig.isAutoGrowingJsSdk();
}
}

@Override
Expand All @@ -62,10 +66,11 @@ private WebViewJavascriptBridgeConfiguration getJavascriptBridgeConfiguration()
String projectId = configurationProvider.core().getProjectId();
String dataSourceId = configurationProvider.core().getDataSourceId();
String appId = configurationProvider.core().getUrlScheme();
String serverUrl = configurationProvider.core().getDataCollectionServerHost();
String appPackage = appInfoProvider.getPackageName();
String nativeSdkVersion = configurationProvider.isDowngrade() ? SDKConfig.SDK_VERSION_DOWNGRADE : SDKConfig.SDK_VERSION;
int nativeSdkVersionCode = configurationProvider.isDowngrade() ? SDKConfig.SDK_VERSION_CODE_DOWNGRADE : SDKConfig.SDK_VERSION_CODE;
return new WebViewJavascriptBridgeConfiguration(projectId, dataSourceId, appId, appPackage, nativeSdkVersion, nativeSdkVersionCode);
return new WebViewJavascriptBridgeConfiguration(projectId, dataSourceId, serverUrl, appId, appPackage, nativeSdkVersion, nativeSdkVersionCode);
}

public void onDomChanged() {
Expand All @@ -81,8 +86,11 @@ public void unregisterDomChangedListener(OnDomChangedListener listener) {
}

@SuppressLint("SetJavaScriptEnabled")
public void bridgeForWebView(SuperWebView<?> webView) {
public void bridgeForWebView(SuperWebView webView) {
webView.setJavaScriptEnabled(true);
if (autoJsSdkInject) {
webView.wrapperWebChromeClient(getJavascriptBridgeConfiguration());
}
if (webView.hasAddJavaScripted()) {
Logger.d(TAG, "JavascriptInterface has already been added to the WebView");
return;
Expand All @@ -93,7 +101,7 @@ public void bridgeForWebView(SuperWebView<?> webView) {
webView.setAddJavaScript();
}

public void getWebViewDomTree(SuperWebView<?> webView, final Callback<JSONObject> callback) {
public void getWebViewDomTree(SuperWebView webView, final Callback<JSONObject> callback) {
Logger.d(TAG, "getWebViewDomTree");
if (callback == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2024 Beijing Yishu Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.growingio.android.hybrid;

import com.growingio.android.sdk.Configurable;

public class HybridConfig implements Configurable {

private boolean autoJsSdkInject = false;

public boolean isAutoGrowingJsSdk() {
return autoJsSdkInject;
}

public HybridConfig setAutoJsSdkInject(boolean autoJsSdkInject) {
this.autoJsSdkInject = autoJsSdkInject;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void onFailed() {
});
}

public SuperWebView<? extends View> getSuperWebView() {
public SuperWebView getSuperWebView() {
if (dom.getView() instanceof WebView) {
return SuperWebView.make((WebView) dom.getView());
} else if (ClassExistHelper.instanceOfX5WebView(dom.getView())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*
* @author cpacm 5/19/21
*/
@GIOLibraryModule
@GIOLibraryModule(config = HybridConfig.class)
public class HybridLibraryGioModule extends LibraryGioModule {
@Override
public void registerComponents(TrackerContext context) {
Expand Down
Loading
Loading