Skip to content

Commit

Permalink
feat: auto inject js sdk in webview. (#222)
Browse files Browse the repository at this point in the history
* auto inject js sdk in webview.

* window._gr_ignore_local_rule = true;

* fix: update hybrid js initialization code

---------

Co-authored-by: styluo <shu_jiahuili@foxmail.com>
  • Loading branch information
cpacm and styluo authored Oct 28, 2024
1 parent 977ae04 commit 637d9f2
Show file tree
Hide file tree
Showing 13 changed files with 719 additions and 31 deletions.
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
12 changes: 6 additions & 6 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.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.2"
growingioCode = "40302"
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 @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,17 @@
import android.os.Build;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

import com.growingio.android.sdk.track.log.Logger;
import com.growingio.android.sdk.track.utils.ReflectUtil;
import com.uc.webview.export.internal.android.WebViewAndroid;

public abstract class SuperWebView<T extends View> {
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

abstract class SuperWebView<T extends View> {
private final T mRealWebView;

protected SuperWebView(T realWebView) {
Expand Down Expand Up @@ -51,6 +58,8 @@ public int getWidth() {

public abstract void evaluateJavascript(String script, ValueCallback<String> resultCallback);

public abstract void wrapperWebChromeClient(WebViewJavascriptBridgeConfiguration bridgeConfiguration);

public boolean hasAddJavaScripted() {
return mRealWebView.getTag(R.id.growing_tracker_has_add_java_script) != null;
}
Expand All @@ -71,7 +80,49 @@ public static SuperWebView<com.uc.webview.export.WebView> makeUC(com.uc.webview.
return new UCWebView(webView);
}

private static final class SystemWebView extends SuperWebView<WebView> {
protected WebChromeClient getWebChromeClientReflect(WebView webView) {
try {
Object provider = ReflectUtil.getFieldRecursive("mProvider", webView);
if (provider == null) return null;
Method providerChromeClientMethod = ReflectUtil.getMethod(provider.getClass(), "getWebChromeClient");
if (providerChromeClientMethod != null) {
return (WebChromeClient) providerChromeClientMethod.invoke(provider);
}
} catch (NoSuchFieldException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (InvocationTargetException ignored) {
} catch (IllegalAccessException ignored) {
} catch (ClassCastException ignored) {
}

return null;
}

protected void setWebChromeClientAvoidThreadCheck(WebView webView, WebChromeClient client) {
try {
Object provider = ReflectUtil.getFieldRecursive("mProvider", webView);
if (provider != null) {
Method method = ReflectUtil.getMethod(provider.getClass(), "setWebChromeClient", WebChromeClient.class);
if (method != null) {
method.invoke(provider, client);
return;
}
}
} catch (NoSuchFieldException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (InvocationTargetException ignored) {
} catch (IllegalAccessException ignored) {
} catch (ClassCastException ignored) {
}

try {
webView.setWebChromeClient(client);
} catch (Exception e) {
Logger.e("SystemWebView", "setDelegateWebChromeClient failed: " + e);
}
}

private static class SystemWebView extends SuperWebView<WebView> {

protected SystemWebView(WebView realWebView) {
super(realWebView);
Expand All @@ -95,6 +146,30 @@ public void evaluateJavascript(String script, ValueCallback<String> resultCallba
getRealWebView().evaluateJavascript(script, resultCallback);
}
}


@SuppressLint("WebViewApiAvailability")
@Override
public void wrapperWebChromeClient(WebViewJavascriptBridgeConfiguration bridgeConfiguration) {
WebView webView = getRealWebView();
if (webView == null) return;

WebChromeClient existChromeClient;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
existChromeClient = webView.getWebChromeClient();
} else {
existChromeClient = getWebChromeClientReflect(webView);
}
if (existChromeClient instanceof WebChromeClientDelegate) {
Logger.d("SystemWebView", "setWebChromeClient: existChromeClient is WebChromeClientDelegate");
return;
}

WebChromeClientDelegate delegateClient = new WebChromeClientDelegate(
existChromeClient == null ? new WebChromeClient() : existChromeClient,
bridgeConfiguration);
setWebChromeClientAvoidThreadCheck(webView, delegateClient);
}
}

private static final class X5WebView extends SuperWebView<com.tencent.smtt.sdk.WebView> {
Expand Down Expand Up @@ -124,6 +199,20 @@ public void onReceiveValue(String s) {
}
});
}

@Override
public void wrapperWebChromeClient(WebViewJavascriptBridgeConfiguration bridgeConfiguration) {
com.tencent.smtt.sdk.WebView webView = getRealWebView();
com.tencent.smtt.sdk.WebChromeClient existChromeClient = webView.getWebChromeClient();
if (existChromeClient instanceof WebChromeClientX5Delegate) {
Logger.d("X5WebView", "setWebChromeClient: existChromeClient is WebChromeClientX5Delegate");
return;
}
WebChromeClientX5Delegate delegateClient = new WebChromeClientX5Delegate(
existChromeClient == null ? new com.tencent.smtt.sdk.WebChromeClient() : existChromeClient,
bridgeConfiguration);
webView.setWebChromeClient(delegateClient);
}
}

private static final class UCWebView extends SuperWebView<com.uc.webview.export.WebView> {
Expand All @@ -146,5 +235,31 @@ public void addJavascriptInterface(Object obj, String interfaceName) {
public void evaluateJavascript(String script, final ValueCallback<String> resultCallback) {
getRealWebView().evaluateJavascript(script, resultCallback);
}

@SuppressLint("WebViewApiAvailability")
@Override
public void wrapperWebChromeClient(WebViewJavascriptBridgeConfiguration bridgeConfiguration) {
com.uc.webview.export.WebView ucWebView = getRealWebView();
if (ucWebView == null || ucWebView.getCoreView() == null || !(ucWebView.getCoreView() instanceof WebViewAndroid)) {
return;
}
WebView webView = (WebViewAndroid) (ucWebView.getCoreView());

WebChromeClient existChromeClient;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
existChromeClient = webView.getWebChromeClient();
} else {
existChromeClient = getWebChromeClientReflect(webView);
}
if (existChromeClient instanceof WebChromeClientDelegate) {
Logger.d("SystemWebView", "setWebChromeClient: existChromeClient is WebChromeClientDelegate");
return;
}

WebChromeClientDelegate delegateClient = new WebChromeClientDelegate(
existChromeClient == null ? new WebChromeClient() : existChromeClient,
bridgeConfiguration);
setWebChromeClientAvoidThreadCheck(webView, delegateClient);
}
}
}
Loading

0 comments on commit 637d9f2

Please sign in to comment.