本文へスキップ

Androidエージェントの適用

WhaTapモバイルエージェントをAndroidアプリに適用すると、画面のロード、ネットワーク呼び出し、クラッシュ、ANR、リソース使用量、WebViewページの性能を収集できます。このドキュメントはアプリ開発者を対象に、ライブラリの追加からデータ収集の確認までの全体の手順を案内します。WebView内のWebページまで収集するには、Web担当者の作業も必要です。詳細はWebViewページ収集の設定で扱います。

サポート環境​

アプリ設定​

ItemValue
minSdk21(Android 5.0)以上
外部依存関係なし
AARのサイズ約380 ~ 400KB

ビルドツール​

Android Gradle Plugin(AGP)7.0以上が必要です。JDKとGradleのバージョンは、使用するAGPの要件にそのまま従います。

AGPJDKGradle
7.x11以上7.0以上
8.x17以上8.x
9.x17以上9.5以上

WebView連携に必要なバージョン​

アプリ内のWebViewページまで併せて収集するには、Androidエージェントとブラウザエージェントの両方が必要バージョンを満たす必要があります。いずれか一方でもバージョンが低いと一部の項目が収集されず、アプリとWebのどちらのログにもエラーは残りません。

ComponentMinimum versionOwner
Androidエージェント2.3.5アプリ開発者
ブラウザエージェント3.2.0Web開発者

適用が完了したら、ダッシュボードのagent_versionの値で実際に動作中のバージョンを確認してください。ファイルを置き換えるだけでは反映の有無が分かりません。ブラウザエージェントファイルのバージョンは、先頭4行のバナーで確認します。

head -4 whatap-browser-agent.js

エージェントのインストール​

次の順序で進めます。

  1. ライブラリの追加
  2. Manifestの設定
  3. SDKの初期化
  4. ProGuardの設定
  5. インストールの確認

ここまで完了すると、画面遷移、リソース、クラッシュ、ANRの収集が開始されます。ネットワーク、WebView、メソッド追跡には追加の作業が必要です。詳細は収集項目で確認してください。

1. ライブラリの追加​

2つの方法のうち1つを選択します。Maven Centralの方式を推奨します。

Maven Central(推奨)​

mavenCentral()がすでに設定されている場合は、リポジトリを追加で設定する必要はありません。Maven Centralで最新バージョンを確認し、<最新バージョン>の箇所に入れてください。

app/build.gradle.kts
dependencies {
implementation("io.whatap.android:whatap-android-agent:<最新バージョン>")
}
app/build.gradle
dependencies {
implementation 'io.whatap.android:whatap-android-agent:<最新バージョン>'
}

リポジトリの宣言がない場合は追加します。

settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
注意

バージョンを+やlatest.releaseで指定しないでください。ビルドのたびにエージェントのバージョンが変わり、問題が発生したときに原因を特定しにくくなります。Maven Centralで最新バージョンを確認し、明示的に指定してください。

AARファイルの直接追加​

閉域網や社内網でMaven Centralにアクセスできない場合に使用します。受け取ったAARファイルをapp/libs/にコピーします。以下の例のファイル名は例示であり、実際に受け取るファイル名は状況によって異なる場合があります。コピーしたファイルの実際の名前に置き換えて指定してください。

app/build.gradle.kts
dependencies {
implementation(files("libs/whatap-agent-bom-complete.aar"))
}
app/build.gradle
dependencies {
implementation files('libs/whatap-agent-bom-complete.aar')
}

2. Manifestの設定​

AndroidManifest.xmlに権限とApplicationクラスを登録します。

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<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" />

<application
android:name=".MyApplication"
...>
</application>
</manifest>

android:nameを登録しないとApplicationクラスが実行されず、SDKが初期化されません。WebViewを連携したアプリでは、ブリッジが「エージェントなし」を返します。するとWebのデータは標準HTTP送信にフォールバックし、ダッシュボードでは通常のブラウザ(BROWSER)として分類されます。デバッグログを有効にすると、アプリのログにAgentが初期化されていませんが残ります。

3. SDKの初期化​

Application.onCreate()で一度だけ呼び出します。アプリにすでにApplicationのサブクラスがある場合は、そのクラスのonCreate()にコードを追加してください。

Kotlin
import android.app.Application
import io.whatap.android.agent.WhatapAgent

class MyApplication : Application() {
override fun onCreate() {
super.onCreate()

WhatapAgent.Builder.newBuilder()
.setProjectKey("<PROJECT_ACCESS_KEY>")
.setPCode(12345) // Int です。L サフィックスを付けるとコンパイルエラー
.setServerUrl("https://<収集サーバードメイン>/m") // 末尾の /m は必須
.setSampling(1.0)
.build(this)
}
}
Java
import android.app.Application;
import io.whatap.android.agent.WhatapAgent;

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();

WhatapAgent.Builder.newBuilder()
.setProjectKey("<PROJECT_ACCESS_KEY>")
.setPCode(12345)
.setServerUrl("https://<収集サーバードメイン>/m")
.setSampling(1.0)
.build(this);
}
}

必須の値は3つです。

MethodDescription
setProjectKey(String)発行されたproject access key
setPCode(int)プロジェクトコード。int型
setServerUrl(String)収集サーバーのbase URL。抜けるとデータが送信されない

その他のオプションはBuilderオプションで確認してください。

注意

初期化の順序を守ってください。

ネットワークライブラリの計測以降に登場するすべてのAPIは、build(this)が完了した後に呼び出す必要があります。その前に呼び出すと、ネットワーク計測は無視され、カスタムログではIllegalStateExceptionが発生します。

4. ProGuardの設定​

minifyEnabled falseのアプリは、この節を飛ばしても構いません。R8が実行されないため、クラス名やメソッド名は変更されません。

minifyEnabled trueの場合は、AARの中にconsumer ProGuardルールが含まれており、自動的に適用されます。画面、ネットワーク、クラッシュ、ANR、リソースなどのネイティブ計測のみを使用する場合は、別途のkeepルールは必要ありません。

WebViewを使用するアプリ​

AARに同梱されたconsumerルールには、WebViewブリッジのメソッドを保存するルールがありません。ブラウザエージェントはブリッジのメソッドを名前で呼び出すため、R8が@JavascriptInterfaceのメソッド名を変更するとブリッジ呼び出しがすべて失敗します。このときwindow.whatapBridgeオブジェクトはそのまま残り、送信経路もブリッジのまま維持されます。個々の呼び出しのみが失敗するため、HTTPフォールバックも動作せず、WebViewのデータが全量失われます。

症状は「releaseビルドでのみWebViewデータが0件、デバッグビルドは正常」という形で現れます。次のルールを追加してください。

app/proguard-rules.pro
# WhaTap WebView ブリッジ。JS がメソッド名で直接呼び出すため名前の保存が必須
-keep class io.whatap.android.agent.webview.** { *; }
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
-keepattributes *Annotation*
-dontwarn io.whatap.android.**

build.gradleのproguardFilesにgetDefaultProguardFile("proguard-android-optimize.txt")またはgetDefaultProguardFile("proguard-android.txt")が含まれている場合、AGPの既定ファイルが@JavascriptInterfaceのルールをすでに含んでいます。上記のルールが必須となるのは、既定ファイルを含めずカスタムルールのみを使用するプロジェクトです。既定ファイルを使用するプロジェクトでも、proguardFilesの構成が変わる場合に備えて明示的に追加することを推奨します。

画面名の可読性​

ダッシュボードの画面名とScreenGroup名は、Activityクラスの単純名から作られます。R8がActivityやFragmentのクラス名を変更する構成の場合、画面名が難読化された値で蓄積されます。データが失われるわけではありませんが、どの画面なのかを判別しにくくなります。必要に応じて次のルールを追加してください。ブリッジの動作には必要ありません。

app/proguard-rules.pro
-keep class * extends android.app.Activity
-keep class * extends androidx.fragment.app.Fragment
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}

5. インストールの確認​

アプリを実行した後、logcatで確認します。エージェントのlogcatタグはすべてwhatapで始まります。

adb logcat | grep -i whatap

Android StudioのLogcatウィンドウを使用する場合は、フィルターにtag:whatapを入力してください。

初期化の成功

✅ WhatapAgentが正常に初期化されました。

サーバー送信の成功

✅ [SpanExporter] HTTP 200 Success (123ms)

データはデフォルトで10秒ごとに送信されるため、アプリを実行した直後にはこのログは出ません。画面を何回か移動した後に再度確認してください。このログが出れば、HTTPリクエストが成功しています。収集サーバーがデータを正常に処理したかどうかは、ダッシュボードにデータが表示されるかで確認してください。

ネットワークリクエストの収集

🌐 [SpanExporter] Starting export for Span: GET (TraceId: ...)
- network_library: OkHttp / Volley / HttpUrlConnection
- http_request_method: GET
- status_code: 200

収集項目​

build(this)が正常に完了すると、次の項目を自動的に収集します。

  • ActivityとFragmentの画面ロード、ScreenGroup
  • クラッシュとANR
  • ユーザーログ
  • CPU、メモリ、温度などのリソース使用量
  • heartbeat

setCollectScreenLoadingまたはsetCollectHeartbeatを無効にすると、その項目のみ収集しません。クラッシュとANRの収集は、build(this)が成功すれば常に有効になります。クラッシュとANRの収集を無効にしたり、レポーターの種類を選択したりするBuilderオプションはありません。iOSのuseNativeCrashReporter()、usePLCrashReporter()はiOS専用であり、Androidのコードに移して使うことはできません。

次の3つの項目は自動的に有効にならず、追加の作業が必要です。

Item必要な作業
ネットワークライブラリのリクエスト・レスポンス情報ネットワークライブラリの計測のwrap()、onRequest()の呼び出し、または自動計測の適用
メソッドの実行時間メソッド実行時間の追跡のCallStackTracerの呼び出し
WebViewページのロードと性能情報WebViewページ収集の設定のブリッジ登録

Builderオプション​

すべてのBuilderオプションは任意であり、指定しない場合は初期値が適用されます。

基本設定​

MethodDefaultDescription
setProjectKey(String)(必須)発行されたproject access key
setPCode(int)(必須)プロジェクトコード
setServerUrl(String)(必須)base URL。/trace、/logが自動的に付く
setTraceServerUrl(String)(自動)traceエンドポイントを直接指定する場合にのみ使用
setLogServerUrl(String)(自動)logエンドポイントを直接指定する場合にのみ使用
setSampling(double)1.0収集比率。0.0 ~ 1.0のスケールであり、50%は0.5。範囲外の値は無視して初期値を維持
注意

setSampling(double)は0.0 ~ 1.0のスケールです。ブラウザエージェントのsampleRateは0 ~ 100のスケールであるため、値をそのまま書き写してはいけません。モバイルの1.0をWebにそのまま入れると、収集比率が1%になります。

収集項目の有効化と無効化​

MethodDefaultDescription
setCollectScreenLoading(boolean)true画面ロードの収集
setCollectNetwork(boolean)trueネットワークの収集
setCollectHeartbeat(boolean)true30秒周期のheartbeat
setScreenGroupDelaySeconds(int)0画面グループのクローズ遅延(秒)。0は無効
setExcludeLifecycleEventsFromScreenGroup(boolean)true画面グループからライフサイクルイベントを除外

setCollectNetwork(false)にすると、ネットワークライブラリの計測のwrap()、onRequest()の呼び出しがすべて何も行わなくなります。ネットワークを計測するには、初期値のtrueを維持してください。

setScreenGroupDelaySeconds(int)の初期値は0です。0の場合、最後のtaskが終わると同時にScreenGroupが閉じます。画面に遷移した後、WebViewのloadUrl()を呼び出すまでに時間がかかると、WebViewのデータがネイティブ画面と別のグループにまとめられることがあります。この場合は3程度を指定して、グループがすぐに閉じないようにしてください。

送信とバッファリング​

トラフィックを減らす必要がある場合に調整します。

MethodDefaultDescription
setFlushIntervalMs(long)10000バッチ送信の周期(ms)
setQueueSize(int)1000メモリキューのサイズ
setMaxDiskBytes(int)512000オフラインディスクバッファの上限(bytes)
setMaxDiskFiles(int)5ディスクバッファファイルの個数。超過時はローテーション
setKeepAliveEnabled(boolean)trueHTTP keep-alive
setMaxConnections(int)5最大同時接続数
setDisconnectAfterSend(boolean)false送信後に接続をすぐ終了
WhatapAgent.Builder.newBuilder()
.setProjectKey("<PROJECT_ACCESS_KEY>")
.setPCode(12345)
.setServerUrl("https://<収集サーバードメイン>/m")
.setCollectHeartbeat(false)
.setFlushIntervalMs(60_000L)
.build(this)

バックグラウンド状態でも、heartbeatとリソースサンプラーが送信される場合があります。使用量が少ない時間帯のトラフィックを減らすには、上の例のようにheartbeatの収集を無効にするか、flushの間隔を長くしてください。

setKeepAliveEnabled(boolean)とsetMaxConnections(int)は、それぞれhttp.keepAliveとhttp.maxConnectionsのJVM system propertyをグローバルに設定します。したがって、アプリでVolleyやHttpURLConnectionを使用している場合は、それらの動作も併せて変わります。初期値の使用を推奨します。

注意

setUserId(String)とsetSessionId(String)に値を指定しても、実際に送信される値には反映されません(現在のリリース版基準)。セッションIDはbuild()の中で新しく作られた値で上書きされます。ユーザーIDはSharedPreferencesの値で決まります。ログインユーザーを反映するには、ログインユーザーIDのWhatapExtra.set(WhatapExtra.USER_ID, ...)を使用してください。

ネットワークヘッダーのキャプチャ​

エージェント2.3.4から対応しています。それ以前のバージョンには以下の3つのメソッドがないため、ビルドが失敗します。

MethodDefaultDescription
setCaptureRequestHeaders(boolean)falserequestヘッダーをhttp.request.header.*のattributeとしてキャプチャ
setCaptureResponseHeaders(boolean)falseresponseヘッダーをhttp.response.header.*のattributeとしてキャプチャ
setHeaderValueMaxLength(int)512ヘッダー値の最大長(bytes)。超過時は切り捨て。0は無制限

オプションを有効にすると、OkHttp、HttpURLConnection、Volley、Apache HttpClientを通過するすべてのHTTPヘッダーが次のルールに従って付与されます。このルールはOpenTelemetry Semantic Conventionsに従います。

RuleExample
ヘッダー名を小文字にし、-を_に変換X-Request-ID → http.request.header.x_request_id
レスポンスヘッダーにも同じルールを適用Set-Cookie → http.response.header.set_cookie
多値ヘッダーはカンマで連結a, b, c
長さ超過時は先頭のみ残して表示...[TRUNCATED to <N>B]
危険

機微なヘッダーの自動マスキングはありません。

Authorization、Cookie、Set-Cookie、X-API-Key、Proxy-Authorizationのような機微なヘッダーも、オプションを有効にすると値がそのままキャプチャされて収集サーバーへ送信されます。有効にする前にキャプチャの範囲を必ず検討し、不要であれば初期値のfalseのままにしてください。

上記のオプションとは関係なく、次のattributeは常に自動的に付与されます(2.3.4以上)。

AttributeTypeDescription
http.request.body.sizelongrequest bodyのサイズ(bytes)
http.response.body.sizelongresponse bodyのサイズ(bytes)

ネットワークライブラリの計測​

AARを追加するだけでは、ネットワークのデータは収集されません。使用しているネットワークライブラリに合わせたコードを自分で追加する必要があります。計測の初期化はbuild(this)が自動的に処理するため、アプリでinit()を別途呼び出す必要はありません。

OkHttp3とRetrofit​

import io.whatap.android.agent.instrumentation.okhttp.OkHttp3Instrumentation

val base = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.build()

val client = OkHttp3Instrumentation.wrap(base)

val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.build()

wrap()が返したclientを使用して初めて計測されます。元のbaseをそのまま使用すると、何も収集されません。

リクエスト単位のattributeが必要な場合は、wrap(client, Config)のオーバーロードを使用してください。リクエスト単位のユーザー定義attributeを参照してください。

Volley​

import io.whatap.android.agent.instrumentation.volley.VolleyInstrumentation;

StringRequest req = new StringRequest(Request.Method.GET, url,
response -> {
// レスポンスの処理
VolleyInstrumentation.onResponseExit(req, response);
},
error -> {
// エラーの処理
VolleyInstrumentation.onErrorExit(req, error);
});

VolleyInstrumentation.onRequest(req);
queue.add(req);

onRequest()はqueue.add()の直前で、onResponseExit()とonErrorExit()は各コールバックの中で呼び出します。3つの地点すべてが必要です。

Volleyは成功コールバックで実際のステータスコードを知ることができないため、成功レスポンスのstatus_codeは一律に200として記録されます。失敗についてはVolleyError.networkResponse.statusCodeから正確な値を取得します。OkHttpとHttpURLConnectionは、実際のコードがそのまま入ります。

HttpURLConnection​

import io.whatap.android.agent.instrumentation.httpurlconnection.HttpUrlConnectionInstrumentation;

HttpURLConnection raw = (HttpURLConnection) url.openConnection();
HttpURLConnection conn = HttpUrlConnectionInstrumentation.wrap(raw);
try {
int code = conn.getResponseCode();
// body の処理
} finally {
conn.disconnect(); // span は wrap が自動的に閉じます
}

wrap()が返したconnを使用して初めて計測されます。元のrawをそのまま使用すると収集されません。

Apache HttpClient​

2つの方法があります。

import io.whatap.android.agent.instrumentation.httpclient.ApacheHttpClientInstrumentation;
import io.whatap.android.agent.instrumentation.httpclient.InstrumentedDefaultHttpClient;

// 方法1. 既存の HttpClient をラップします
HttpClient client = ApacheHttpClientInstrumentation.wrap(existingClient);

// 方法2. DefaultHttpClient を使用していた場合はドロップイン置換(2.2.6 以上)
HttpClient client2 = new InstrumentedDefaultHttpClient();

InstrumentedDefaultHttpClientはattributeのチェーンを提供します。

HttpClient client3 = new InstrumentedDefaultHttpClient()
.addAttribute("module", "payment")
.setResponseAttributeExtractor(resp -> {
Map<String, Object> a = new HashMap<>();
a.put("biz.status", resp.getStatusLine().getStatusCode());
return a;
});

Apache HttpClientはAndroid 6.0からプラットフォームで削除されているため、ビルド設定に次が必要です。

app/build.gradle.kts
android {
useLibrary("org.apache.http.legacy")
}

この前提条件を適用できない場合は、OkHttpやHttpURLConnectionなど別のネットワーククライアントを使用してください。

リクエスト単位のユーザー定義attribute​

エージェント2.2.6から、リクエストごとに追加のattributeを付与できます。次はVolleyを例とした記述です。

VolleyInstrumentation.configure(req)
.addAttribute("module", "payment")
.addAttribute("tenant_id", "demo")
.setRequestAttributeExtractor(r -> {
Map<String, Object> a = new HashMap<>();
a.put("biz.user_id", extractFromQuery(r.getUrl()));
return a;
})
.setResponseAttributeExtractor(resp -> {
Map<String, Object> a = new HashMap<>();
if (resp instanceof String) a.put("biz.body_len", ((String) resp).length());
return a;
});
queue.add(req);

OkHttpとHttpURLConnectionは、wrap(client, Config)のオーバーロードに同じ形式のConfigを渡します。付与した値は送信JSONのmetrics.extrasに入り、ダッシュボードに表示されます。

自動計測(任意)​

Gradleプラグインを適用すると、バイトコードを注入してネットワークライブラリとメソッドの実行時間を自動的に計測します。そのため、前の節で説明したwrap()やonRequest()の呼び出しをコードに直接入れる必要はありません。

Project レベルの build.gradle.kts
plugins {
id("io.whatap.android") version "<最新バージョン>" apply false
}
app/build.gradle.kts
plugins {
id("com.android.application")
id("io.whatap.android")
}
Project レベルの build.gradle
plugins {
id 'io.whatap.android' version '<最新バージョン>' apply false
}
app/build.gradle
plugins {
id 'com.android.application'
id 'io.whatap.android'
}

閉域網でプラグインのJARを直接使用するには、libs/または社内Mavenリポジトリに配置し、buildscriptから参照します。

Project レベルの build.gradle.kts
buildscript {
dependencies {
classpath(files("libs/whatap-android-plugin-<最新バージョン>.jar"))
}
}

WebViewブリッジの登録は、プラグインを適用しても自動的には処理されません。WebViewページ収集の設定を別途進めてください。

メソッド実行時間の追跡​

特定のメソッドの実行にかかる時間を測定します。WhatapAgentがすでに初期化されていれば、最初の呼び出し時に自動的に準備されるため、別途の初期化は必要ありません。

計測パターン​

パターン1から3はエージェント2.2.8から、パターン4は2.2.9から対応しています。

import java.util.concurrent.Callable;
import io.whatap.android.agent.instrumentation.stacktrace.CallStackTracer;
import io.whatap.android.agent.instrumentation.stacktrace.StackSpan;

// パターン1. try-with-resources。メソッド本文全体をラップする場合
try (AutoCloseable s = CallStackTracer.scope("PaymentService", "charge")) {
// 測定するロジック
}

// パターン2. 戻り値なし
CallStackTracer.measure("PaymentService", "charge", () -> doCharge());

// パターン3. 戻り値あり、checked exception を伝播
Receipt r = CallStackTracer.measure("PaymentService", "charge",
(Callable<Receipt>) () -> doChargeReturn());

// パターン4. StackSpan。開始地点と終了地点が離れている場合
StackSpan span = CallStackTracer.start("PaymentService", "charge");
try {
// 測定するロジック
span.end();
} catch (RuntimeException e) {
span.endWithError(e); // エラー情報とともに終了
}
状況推奨パターン
メソッド本文全体を1行でラップパターン1 scope
ラムダでラップでき、戻り値なしパターン2 measure(Runnable)
ラムダでラップでき、戻り値ありパターン3 measure(Callable)
開始と終了が離れている、または別スレッドで終了パターン4 StackSpan

StackSpanはAutoCloseableを継承しているため、try-with-resourcesでも使用できます。すでに終了またはキャンセルしたspanに再度呼び出しても、何も起こりません。span.cancel()は記録も送信も行いません。

計測対象の選び方​

すべてのメソッドを計測する必要はありません。あまりに多くのメソッドを計測すると、不要なデータが増えるだけです。

優先順位対象例
1ユーザーアクションの入口Activity.onCreate、Fragment.onViewCreated、クリックハンドラー
2ビジネストランザクションの境界決済、送金、認証、精算
3ネットワークとDB呼び出しのwrapperRepository.findX、ApiService.callY
4バックグラウンドの重い処理画像処理、暗号化・復号、シリアライズ
不適切getter、setter、単純な変換、短いループ10msのフィルターにかかって破棄され、ノイズが増えるだけ

動作の仕組み​

  • 実行時間が10ms未満の場合は送信しません。設定で変更できず、endWithError()で終了したspanも同様です。
  • 10秒ごとにバッチで送信します。
  • バックグラウンドスレッドでも独立して動作します。ThreadLocalベースです。
  • 再帰呼び出しは安全です。ただし、深さの累積には注意してください。

logcatで次のように収集状況を確認できます。

CallStackLogRecordCollector initialized
CallStack LogRecord Collector started - interval: 10000ms
First log added: MainActivity.loadData
Scheduled flush triggered - buffer size: 3
Collected 3 records from buffer
Sending batch with 3 records
✅ [LogExporter] HTTP 200 Success (85ms)

Skipping (< 10ms): MainActivity.onCreate duration=4msは正常な動作です。10ms未満のメソッドを除外したものです。

画面グループの設定​

画面遷移のデータは、build(this)を呼び出すだけで収集されます。複数のActivityやFragmentにまたがるフローを1つのグループにまとめたい場合にのみ、この節の設定が必要です。

ノート

エージェント2.3.xで、従来のstartGroup()、addTask()、endGroup()のAPIがstartChain()、endChain()に変わりました。

フローを自分で管理する​

開始画面でstartChain()、終了画面で同じtaskIdでendChain()を呼び出します。taskIdをnullにすると自動生成され、getCurrentChainTaskId()で照会します。

import android.content.Intent
import io.whatap.android.agent.instrumentation.screengroup.ChainView

private const val EXTRA_CHAIN_TASK_ID = "whatap_chain_task_id"

class LoginActivity : AppCompatActivity() {
private fun continueToConfirmation() {
ChainView.getInstance().startChain("LoginFlow", null)
val taskId = ChainView.getInstance().getCurrentChainTaskId() ?: return

startActivity(Intent(this, ConfirmationActivity::class.java)
.putExtra(EXTRA_CHAIN_TASK_ID, taskId))
}
}

class ConfirmationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent.getStringExtra(EXTRA_CHAIN_TASK_ID)?.let { taskId ->
ChainView.getInstance().endChain(taskId)
}
}
}
注意

チェーンは一度に1つだけ維持されます。終了する前に再度startChain()を呼び出すと、前のチェーンのtaskIdが失われ、endChain()が動作しません。

チェーンの状態と終了待機時間​

isChainActive()を使用すると、現在進行中のチェーンがあるかを確認できます。画面と画面の間に短い空白がある場合は、終了待機時間を延ばして1つのグループとして維持してください。初期値は0であり、この場合は最後の画面が終わると同時にグループが閉じます。

val isChainActive = ChainView.getInstance().isChainActive()

WhatapAgent.Builder.newBuilder()
.setScreenGroupDelaySeconds(3)
.build(this)

カスタムログとグローバルattribute​

注意

この節のAPIは、build(this)の完了後に呼び出す必要があります。初期化前に呼び出すとIllegalStateExceptionが発生します。

カスタムログ​

import io.whatap.android.agent.instrumentation.userlog.UserLogger;

UserLogger.print("決済開始");

Map<Object, Object> m = new HashMap<>();
m.put("event_name", "checkout");
m.put("amount", 12000);
UserLogger.print(m);

print()の呼び出し1回がログ1件です。送信はsetFlushIntervalMs(初期値10秒)の周期であるため、呼び出した直後にダッシュボードへすぐ表示されるわけではありません。

print(Map)のキーは<key>.cとして、print(String)はmessages.cとして送信されます。event_nameを入れても、SDKが付与する値を上書きすることはありません。

グローバルattribute​

以降に送信されるすべてのspanとlogに、同じ値を共通で追加できます。

import io.whatap.android.agent.extra.WhatapExtra;

WhatapExtra.set("tenant_id", "acme");
WhatapExtra.remove("tenant_id");

値はmetrics.extras.<key>.cとして送信されます。リクエスト単位のattributeはリクエスト単位のユーザー定義attributeを参照してください。

ログインユーザーID​

WhatapExtra.USER_IDは特別扱いされる予約キーです。

WhatapExtra.set(WhatapExtra.USER_ID, "ユーザーID");

送信metaとWebViewブリッジのgetUserId()が併せて更新され、ネイティブ画面とWebView画面が同じユーザーとしてまとめられます。指定しない場合は、端末ごとの匿名IDが自動生成されて維持されます。

WebViewページ収集の設定​

アプリのWebViewに表示されるWebページは、ネイティブSDKではなくブラウザエージェントが収集します。ネイティブ画面とWebViewページを同じセッションで紐付けるには、アプリとWebの両方を設定する必要があります。

  1. 収集サーバーアドレスの確認
  2. WebViewの登録
  3. ブラウザエージェントスクリプトの追加

3つの段階をすべて完了して初めて連携が完了します。いずれか1つでも欠けると、ブリッジに到達できなかったデータは標準HTTP方式で送信されます(ブラウザエージェントのオプションwebViewHttpFallback、初期値true)。この場合、データ自体は収集されます。しかしダッシュボードでは通常のブラウザ(BROWSER)として分類され、ネイティブセッションとは紐付きません。フォールバックはデータが消えるのを防ぐための安全網にすぎず、連携が完了したという意味ではありません。

必要バージョンは、Androidエージェント2.3.5以上、ブラウザエージェント3.2.0以上です。WebView連携に必要なバージョンを先に確認してください。

組み合わせ別の収集項目​

Android 14の実機と実際の収集サーバーで検証した結果です。

Item標準適用連携適用、ブリッジ接続連携適用、ブリッジ未到達
ページロード○○○(フォールバック)
リソース、AJAX○○○(フォールバック)
画面遷移○○○(フォールバック)
JSエラー5種○○○(フォールバック)
ユーザーイベント○○○(フォールバック)
セッションリプレイ○○○(フォールバック)
Core Web Vitals○○○(フォールバック)
カスタムログ○✗○(フォールバック)
ダッシュボードの分類BROWSERWEBVIEWBROWSER
蓄積されるプロジェクトWebページのpcodeアプリのモバイルプロジェクトWebページのpcode
ネイティブとのセッション統合-○✗

標準適用はブラウザエージェントをisWebViewなしで初期化した状態であり、連携適用はisWebView: trueで初期化した状態です。JSエラー5種とは、uncaughtエラー、unhandled promise rejection、console.error()、noticeError()、CSP violationです。

注意

カスタムログは連携適用では収集されません。

ブラウザエージェントはカスタムログ(enableCustomLogとlogger)をブリッジメソッドlogに送りますが、モバイルブリッジに該当するインターフェイスがないため静かに破棄されます。デバッグモードではbridgeRequest:androidMethodMissingとして現れます。カスタムログが必要なページは、isWebViewを指定せず標準適用のままにしてください。

データが蓄積されるプロジェクト​

連携が動作している間、Webのデータはアプリのモバイルプロジェクトに蓄積されます。ページに設定したpcodeやprojectAccessKeyには入りません。ブリッジに渡されたデータは、アップロードの直前にプロジェクト識別値をアプリのsetPCode、setProjectKeyの値に合わせます。sessionIDとuserIDもネイティブの値に統一されます。ネイティブ画面とWebView画面を1つのセッションとして確認するには、2つのデータが同じプロジェクトにある必要があります。そのために、2つの構成要素が同じ規格を使用します。

Case照会するプロジェクト
標準適用(isWebView未設定)Webページのpcode
連携適用、ブリッジ接続済みアプリのモバイルプロジェクトのpcode
連携適用、ブリッジ未到達(フォールバック)Webページのpcode

したがって、ページのpcodeとprojectAccessKeyはフォールバックで送信する場合にのみ使用します。連携が正常に動作している間は使用しません。ただし、ブリッジが切れる場合に備えて、ブラウザ(RUM)プロジェクトの有効な値を入れる必要があります。任意の値やアプリのモバイルpcodeを入れても、初期化段階の形式チェックは通過します。しかし、フォールバックで送信されたデータはどこにも蓄積されません。

iOSアプリとAndroidアプリが互いに異なるモバイルプロジェクトを使用している場合、同じWebページのWebViewデータもプラットフォーム別に分かれて蓄積されます。HTMLをアプリごとに分ける必要はありません。1つのWeb画面の全体の指標を確認するには、2つのプロジェクトをそれぞれ照会してください。

1. 収集サーバーアドレスの確認​

モバイルエージェントのsetServerUrlの値です。WebViewのデータもこのアドレスへ送信されるため、連携では特に重要です。

RuleExample
スキーム、ホスト(ポート)、/mの順で終わるhttps://収集サーバーアドレス:9443/m
リバースプロキシのパスを含めることが可能https://内部ホスト:9443/22/m
末尾に/を付けないhttps://…/m/は…/m//pageLoadとなり失敗する

AndroidエージェントはWebViewのデータにのみ/mを補正します。アドレスがすでに/mで終わっている場合は、重ねて付けることはありません。したがって/mを付け忘れると、WebViewのデータは届くもののネイティブのデータが失われる場合があります。常に/mを含めてください。

社内のリバースプロキシを前段に置き、プロキシのパスを含む値を使用しても構いません。エージェントはこの値の後ろに必要なパスをそのまま連結します。したがって、プロキシが次のパスをすべて転送するように設定すれば十分です。

Data<serverUrl>の後ろに付くパス
ネイティブのトレース、ログ/trace /log
WebViewのページロード/pageLoad
リソース、画面遷移、エラー、イベント、メモリ/resource /routeChange /onError /event /memory
Web Vitals/webVitals /v2/webVitals
セッションリプレイ/sessionreplay /v2/sessionreplay

2. WebViewの登録​

WebViewのインスタンスごとに登録する必要があります。必ずloadUrl()を呼び出す前に、UIスレッドで登録してください。ブリッジが動作するには、SDKの初期化とManifestの設定が先に完了している必要があります。

まず使用するメソッドを決めてください。アプリにカスタムWebViewClientがあるかどうかで、使用するメソッドが変わります。

既存のWebViewClient登録メソッド
なしsetupWebView(webView, null)
以下の6つのコールバックのみをオーバーライドsetupWebView(webView, myClient)
それ以外のコールバックを1つでもオーバーライドattachBridgeOnly(webView)単独
危険

カスタムWebViewClientがある場合は、setupWebView()とwrapWebViewClient()を使う前に必ず確認してください。

ラッパーが既存のクライアントへ転送するコールバックは、次の6つだけです。

  • onPageStarted
  • onPageFinished
  • onReceivedError(WebView, int, String, String)
  • onPageCommitVisible
  • onLoadResource
  • shouldOverrideUrlLoading(WebView, String)

転送しないコールバックは、shouldOverrideUrlLoading(WebView, WebResourceRequest)、onReceivedError(WebView, WebResourceRequest, WebResourceError)、onReceivedSslError、shouldInterceptRequest、onReceivedHttpError、onReceivedHttpAuthRequest、onRenderProcessGone、doUpdateVisitedHistory、onFormResubmission、onReceivedClientCertRequestです。

特に、API 24以上で使用するshouldOverrideUrlLoading(WebView, WebResourceRequest)をオーバーライドしている場合は、URLの横取り、外部アプリへの遷移、ダウンロードのインターセプトが動作しません。onReceivedSslErrorで社内証明書を通過させていた場合は、該当ページもロードされません。このような場合はattachBridgeOnly()のみを使用してください。

次は、カスタムWebViewClientの有無に関係なく安全なattachBridgeOnly()の方式です。

import android.webkit.CookieManager;
import android.webkit.WebView;
import io.whatap.android.agent.webview.WhatapWebviewBridge; // Webview。v が小文字です

private WhatapWebviewBridge whatapBridge; // インスタンスフィールド(static 共有は禁止)
private boolean whatapAttached; // 再入ガード

private void initWhatap(WebView webView) {
if (whatapAttached) return;

// Android の初期値は false です。エージェントがこの値を代わりに有効にすることはありません
webView.getSettings().setJavaScriptEnabled(true);

// 以下の2行は HTTP フォールバック区間のセッション維持とサンプリングの連続性に使われます
webView.getSettings().setDomStorageEnabled(true);
CookieManager.getInstance().setAcceptCookie(true);

// Activity/Fragment の this ではなく applicationContext(ブリッジが Context を永続保持)
whatapBridge = new WhatapWebviewBridge(webView.getContext().getApplicationContext());
whatapBridge.attachBridgeOnly(webView); // 既存の WebViewClient には触れません
whatapAttached = true;
}

private void openPage(WebView webView, String url) {
initWhatap(webView); // 登録が先
webView.loadUrl(url); // その次にロード
}

Jetpack Composeでは、factoryラムダの中で登録します。

import android.webkit.WebView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import io.whatap.android.agent.webview.WhatapWebviewBridge

@Composable
fun WhatapWebView(url: String) {
val appContext = LocalContext.current.applicationContext
val bridge = remember { WhatapWebviewBridge(appContext) }

AndroidView(
factory = { ctx ->
WebView(ctx).apply {
settings.javaScriptEnabled = true
bridge.attachBridgeOnly(this) // loadUrl の前に登録
loadUrl(url)
}
}
)
}

カスタムWebViewClientがない場合、または上記6つのコールバックのみを使用する場合は、attachBridgeOnly(webView)の箇所をsetupWebView(webView, null)またはsetupWebView(webView, myClient)に置き換えてください。ブリッジの接続とともに、ネイティブのページロードspanまで収集します。

attachBridgeOnly()のみを使用しても、ページロード、リソース、エラー、Web Vitals、セッションリプレイなどのWebデータはすべて収集されます。収集されないのは、アプリが作るネイティブのページロードspan 1つだけです。このデータはWeb側のendPageLoad()の呼び出しで代替できます。

attachBridgeOnly()を使用しながらネイティブのページロードspanまで収集するには、wrapWebViewClient()ではなく継承を使用してください。こうすると、アプリがオーバーライドした最新のコールバックもそのまま維持されます。

import android.graphics.Bitmap;
import android.webkit.WebView;
import io.whatap.android.agent.webview.WhatapWebViewClient; // WebView。V が大文字です
import io.whatap.android.agent.webview.WhatapWebviewBridge; // Webview。v が小文字です

class MyWebViewClient extends WhatapWebViewClient {
MyWebViewClient(WhatapWebviewBridge bridge) { super(bridge); }

@Override
public void onPageStarted(WebView v, String url, Bitmap favicon) {
super.onPageStarted(v, url, favicon); // super の呼び出しは必須
// 既存のロジック
}
}

上のinitWhatap()のattachBridgeOnly()の後ろに1行追加します。継承したからといってattachBridgeOnly()が不要になるわけではありません。ブリッジの注入とページロードの追跡は別々の作業であるため、両方が必要です。

whatapBridge.attachBridgeOnly(webView);                        // ブリッジの注入(必須)
webView.setWebViewClient(new MyWebViewClient(whatapBridge)); // ページロード追跡の追加

登録メソッド

MethodDescription
attachBridgeOnly(WebView)ブリッジのみを接続し、WebViewClientは変更しない。カスタムクライアントがある場合はこのメソッドを使用
setupWebView(WebView, WebViewClient)ブリッジの接続とWebViewClientのラッピングを一度に処理。上記6つのコールバックのみを使用する場合に限り使用
wrapWebViewClient(WebViewClient)既存のWebViewClientにページロード追跡を追加したラッパーを返す。setupWebView()と同じ制約
configureWebView(WebView)サポートが終了したメソッド。attachBridgeOnly()と同じ動作だが、ページロード追跡が抜ける。使用禁止

WebViewの設定

Setting必要な理由
setJavaScriptEnabled(true)Androidの初期値がfalseであり、エージェントが代わりに有効にしないため
setDomStorageEnabled(true)HTTPフォールバック区間のセッション維持とサンプリングの連続性に使用
CookieManager.setAcceptCookie(true)上と同じ

サードパーティCookieは有効にする必要はありません。ブラウザエージェントが使用するCookieは、domain属性のないhost-onlyのSameSite=Lax Cookieです。収集サーバーへデータを送信する際にも資格情報を使用しません。CookieManager.setAcceptThirdPartyCookies()は必要ありません。

アプリを終了する前にCookieを保存すると、フォールバック区間の匿名ユーザーIDがアプリの再起動後も維持されます。

CookieManager.getInstance().flush();

登録のルール

Rule守らない場合
loadUrl()より前に登録ページがブリッジなしでロードされ、そのページのデータが失われる
UIスレッドで呼び出すブリッジのコンストラクターはHandlerを作り、attachBridgeOnly()はaddJavascriptInterface()を呼び出すため、別スレッドで呼び出すと例外がアプリに伝播する。非同期のフローであればwebView.post(() -> initWhatap(webView))でラップすること
WebViewインスタンスごとに1回だけ登録セッションとページロードの追跡がずれ、不要なリソースが残る。1つのWebViewで複数のURLをロードしても、登録は最初の1回で十分。上の例のwhatapAttachedのような再入ガードが必要
コンストラクターにapplicationContextを渡すブリッジがContextを永続保持するため、Activityのthisを渡すと画面が消えた後も参照が残りリークが発生する
ブリッジのインスタンスをフィールドで保持し、staticで共有しない複数のWebViewが同じブリッジを共有すると、画面の紐付けがずれる
setupWebView()の後にsetWebViewClient()を再度呼び出さないラッパーが置き換わり、ページロードの追跡が消える。ブリッジには影響しないため、「Webデータは届くがページロードだけがない」という形で現れる
自社コンテンツをロードするWebViewにのみ登録登録したWebView内でロードされるコンテンツは、iframeを含めブリッジにアクセス可能。外部リンク、広告、規約リンクを開くWebViewには登録禁止

必ずonCreate()で登録する必要はありません。FragmentではonViewCreated()で登録します。WebViewを動的に生成する場合はnew WebView(context)の直後、Composeではfactoryラムダの中で登録します。restoreState()もページを再度ロードするため、その前に登録してください。

ノート

startDataUploadTimer()は呼び出さないでください。以前のインストール画面の例にはこのコードが残っていますが、現在のAndroidエージェントはブリッジのメソッドが呼び出されるたびにデータをすぐ送信します。したがって、このタイマーが空にする内部キューを使用しません。startDataUploadTimer()を呼び出しても、空のキューを確認するタイマーが1つ増えるだけです。

minifyを使用するビルドの場合は、ProGuardの設定のkeepルールも併せて確認してください。

3. ブラウザエージェントスクリプトの追加​

WebViewが開くすべてのHTMLページのheadタグ最上部に、次のスクリプトを入れてください。Web担当者が進める作業です。

非同期方式はページロードの性能に影響を与えません。ただし、エージェントが実行される前に発生したajaxとerrorのデータは収集されない場合があります。

Async
<script>
(function (w, h, _a, t, a, b) {
w = w[a] = w[a] || {};
w.config = {
projectAccessKey: "{PROJECT_ACCESS_KEY}",
pcode: {PCODE},
sampleRate: 100,
isWebView: true,
proxyBaseUrl: "https://rum-ap-northeast-2.whatap-browser-agent.io/",
};
a = h.createElement(_a);
a.async = 1;
a.src = t;
t = h.getElementsByTagName(_a)[0];
t.parentNode.insertBefore(a, t);
})(window, document, 'script', 'https://repo.whatap-browser-agent.io/rum/prod/v2/whatap-browser-agent.js', 'WhatapBrowserAgent', '');
</script>

ページロード時点のデータを漏れなく収集するには、同期方式を使用してください。ページロードの性能に影響を与える場合があります。

Sync
<script>
window.WhatapBrowserAgent = {
config: {
projectAccessKey: "{PROJECT_ACCESS_KEY}",
pcode: {PCODE},
sampleRate: 100,
isWebView: true,
proxyBaseUrl: "https://rum-ap-northeast-2.whatap-browser-agent.io/",
},
};
</script>
<script src="https://repo.whatap-browser-agent.io/rum/prod/v2/whatap-browser-agent.js" type="text/javascript"></script>
注意

設定キーとスクリプトアドレスはそのまま書き写してください。

  • isWebViewは大文字と小文字を区別します。isWebviewのように記述すると、不明なキーとして警告なしに無視され、ネイティブセッションとつながりません。
  • WebView用のスクリプトアドレスは/rum/prod/v2/whatap-browser-agent.jsです。v1のアドレスにはBridge連携がありません。
  • Asyncスニペットの5番目の引数'WhatapBrowserAgent'は変更しないでください。この値は設定を格納するグローバルオブジェクトの名前です。この値をバンドルのパスに変えると、エージェントが設定を見つけられません。このときコンソールに別途のメッセージも出ず、初期化も行われません。エージェントファイルを自社でホスティングする場合は、バンドルのパスを指定する4番目の引数を変更してください。
ConfigDescription
projectAccessKeyブラウザ(RUM)プロジェクトのアクセスキー。フォールバック送信に使用
pcodeブラウザ(RUM)プロジェクトのプロジェクトコード。フォールバック送信に使用
sampleRate収集比率(%)。0 ~ 100のスケールであり、モバイルエージェントのsetSampling(0.0 ~ 1.0)とは異なる。適用確認中は100を使用
isWebViewデータ送信をモバイルエージェントに委任するスイッチ。連携適用ではtrueを指定
proxyBaseUrlフォールバック送信時にデータを送るアドレス。連携適用でも必須。設定しないとデータがまったく送信されない

projectAccessKey、pcode、proxyBaseUrlの値は、ブラウザ(RUM)プロジェクトの管理 > エージェントインストール画面で、現在のプロジェクトの値が入力された状態で確認できます。

適用の有無は、該当ページのブラウザコンソールで確認します。

typeof window.WhatapBrowserAgent   // 'object' であれば適用された状態

WebViewブリッジの確認​

ブリッジが実際に注入されたかを確認するには、WebViewデバッグを有効にしたうえで、PCのChromeから確認します。

WebView.setWebContentsDebuggingEnabled(true);   // 確認後は必ず削除

PCのChromeでchrome://inspectにアクセスして該当WebViewをinspectし、コンソールで確認します。

typeof window.whatapBridge;              // 'object'
typeof window.whatapBridge.pageLoad; // 'function'
typeof window.whatapBridge.getSessionId; // 'function'
注意

minifyを使用している場合は、メソッド単位まで確認してください。

デバッグビルドはkeepルールがなくても正常に動作します。したがって、minifyEnabled trueのビルドでも上記の方法で確認してください。window.whatapBridgeは'object'と表示されるのにpageLoadが'undefined'であれば、keepルールが抜けています。ProGuardの設定を確認してください。

トラブルシューティング​

データがまったく収集されません​

  1. setServerUrl()を指定したかを確認してください。抜けると送信されません。
  2. AndroidManifest.xmlの<application android:name=".MyApplication">の登録を確認してください。
  3. INTERNET権限があるかを確認してください。
  4. logcatに✅ WhatapAgentが正常に初期化されました。が出力されるかを確認してください。
  5. setProjectKeyとsetPCodeの値が、発行された値と一致するかを確認してください。
  6. プロキシやファイアウォールの設定で送信がブロックされていないかを確認してください。

ネットワークデータのみ収集されません​

  1. wrap()が返したオブジェクトを使用しているかを確認してください。元のオブジェクトをそのまま使うと収集されません。
  2. setCollectNetwork(false)で無効にしていないかを確認してください。
  3. VolleyはonRequest()、onResponseExit()、onErrorExit()の3つの地点すべてが必要です。

メソッド追跡のイベントが表示されません​

  1. 測定対象が10ms以上かかるかを確認してください。それ未満は自動的に除外されます。
  2. 送信は10秒のバッチです。最低10秒以上待ってみてください。
  3. [CallStackTracer] ⏭️ Skipping (< 10ms)のログが見えれば、正常に除外されています。

イベントが多く収集されすぎる場合は、計測する地点を減らしてください。getter、setter、単純な変換メソッドには計測を入れないことをお勧めします。計測対象の選び方を参照してください。

WebViewのデータが収集されません​

症状原因対処
WebViewのデータがどこにも見当たらないWebページのpcodeを照会しているアプリのモバイルプロジェクトを照会
データは届くが通常のブラウザとして分類されるWebViewの登録がページロードより遅い登録の後にロードする順序を確認。ブラウザエージェントは初期化の時点で1回だけWebView環境を判別するため、ロード後にブリッジが注入されても送信経路は変わらない
データは届くが通常のブラウザとして分類されるSDKの初期化漏れ。android:nameが未登録、またはbuild(this)が未呼び出しManifestの設定とSDKの初期化を確認
データがまったく収集されないproxyBaseUrlが未設定連携適用でも設定する
releaseビルドでのみWebViewデータが0件R8が@JavascriptInterfaceのメソッドをリネームProGuardの設定のkeepルールを確認
ネイティブのデータのみ失われる(WebViewは正常)setServerUrlが/mで終わっていない/mを追加
すべてのリクエストが404setServerUrl末尾の/によりパスが//で生成される末尾の/を削除
データがほとんど届かない(約1%)モバイルの1.0をWebのsampleRateにそのまま入力Webは0 ~ 100のスケール。sampleRate: 100を指定
アプリのURLの横取り、SSL例外処理が壊れるsetupWebView()、wrapWebViewClient()が最新のWebViewClientコールバックを委譲しないattachBridgeOnly()単独に切り替え
カスタムログのみ収集されない連携適用ではブリッジがlogを処理しない該当ページは標準適用のまま維持
WebViewのデータがネイティブ画面と別のグループにまとめられるネイティブ画面のロードが終わってScreenGroupがすでに閉じた後にWebViewのデータが届くsetScreenGroupDelaySeconds(3)で終了を遅延、または画面遷移とloadUrl()の間隔を短縮
アプリの再起動ごとにセッションが新規作成されるCookieの保存漏れ、またはDOMストレージが無効CookieManager.flush()とsetDomStorageEnabled(true)を確認

正常に連携されると、Mobileダッシュボードでネイティブ画面とWebViewページが同じセッションに時系列で表示されます。WebViewダッシュボードでは、ページロード、Web Vitals、リソースタイミングを確認できます。

アプリの起動時にNoClassDefFoundErrorが発生します​

AARを直接追加した場合は、受け取ったファイルのサイズが約380 ~ 400KBであるかを確認してください。ファイルサイズがこの範囲と大きく異なる場合は、ファイルが正常ではないため、再度送付を依頼してください。Maven Centralの座標を使用すれば、この問題は発生しません。

ビルドエラーが発生します​

Plugin not foundエラー

自動計測のGradleプラグインが見つからない場合は、次の設定を追加します。

settings.gradle
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}

Javaバージョンのエラー

まずビルドツールでAGP、JDK、Gradleの対応関係を確認してください。class file has wrong versionエラーは、ビルドに使用するJDKのバージョンが低い場合に発生します。ビルドに使用するJDKと、アプリのsourceCompatibilityは互いに別のものです。

Namespaceの警告

Namespace 'io.whatap.android.agent' is used in multiple modulesの警告は無視して構いません。ライブラリを複数のモジュールで使用しているという意味であり、アプリの実行には影響しません。

その他のビルドエラー

  • GradleのバージョンとAGPのバージョンがビルドツールの要件を満たしているかを確認してください。
  • ネットワークの接続状態を確認し、必要であればプロキシを設定してください。
  • プロジェクトをClean & Rebuildしてください。
  • リリースビルドでのみアプリが落ちる場合は、他のライブラリのProGuardルールと競合していないかを確認してください。

サポートの依頼​

技術サポートを依頼する際に次の情報を併せてお伝えいただくと、より早く解決できます。

  • プロジェクトアクセスキー
  • エージェントバージョンとAndroid SDKバージョン
  • GradleバージョンとAndroid Gradle Pluginバージョン
  • logcatの全スタックトレース
  • build.gradleファイルの内容