Androidワークスペース統合ガイド
Androidワークスペース統合ガイド
概要
本ガイドでは、AndroidアプリにGPTBotsワークスペースを統合する方法について、権限申請、ネイティブとH5の連携、その他設定を含めて詳しく説明します。
GPTBotsはワークスペースのDEMOプロジェクトも提供しており、迅速な導入が可能です。Android用DEMOプロジェクト:Android端DEMOプロジェクト
権限一覧
基本権限
ワークスペース機能を正常に利用するため、AndroidManifest.xmlに以下の権限を設定してください。
<!-- ネットワーク権限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 録音権限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- ストレージ権限 -->
<!-- Android 13未満 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 13以上 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- その他補助権限 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- ネットワーク権限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 録音権限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- ストレージ権限 -->
<!-- Android 13未満 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 13以上 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- その他補助権限 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
このコードブロックをポップアップで表示
権限処理
アプリ起動時に、マイク・カメラ・アルバム等の実行時権限を動的にリクエストしてください。
// Android 13以上で必要な権限
private final String[] permissionsForAndroid13 = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_MEDIA_VIDEO
};
// Android 13未満で必要な権限
private final String[] permissionsForBelowAndroid13 = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
// Android 13以上で必要な権限
private final String[] permissionsForAndroid13 = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_MEDIA_VIDEO
};
// Android 13未満で必要な権限
private final String[] permissionsForBelowAndroid13 = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
このコードブロックをポップアップで表示
WebView設定
基本設定
WebViewインスタンス生成時の推奨設定:
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true); // JavaScript有効化
webSettings.setDomStorageEnabled(true); // DOMストレージAPI有効化
webSettings.setAllowFileAccess(true); // ファイルアクセス許可
webSettings.setAllowContentAccess(true); // コンテンツURLアクセス許可
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); // 混在コンテンツ許可
webSettings.setMediaPlaybackRequiresUserGesture(false); // ユーザー操作不要でメディア再生
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true); // JavaScript有効化
webSettings.setDomStorageEnabled(true); // DOMストレージAPI有効化
webSettings.setAllowFileAccess(true); // ファイルアクセス許可
webSettings.setAllowContentAccess(true); // コンテンツURLアクセス許可
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); // 混在コンテンツ許可
webSettings.setMediaPlaybackRequiresUserGesture(false); // ユーザー操作不要でメディア再生
このコードブロックをポップアップで表示
録音関連設定
webSettings.setAllowFileAccessFromFileURLs(true); // ファイルURLからのアクセス許可
webSettings.setAllowUniversalAccessFromFileURLs(true); // ユニバーサルアクセス許可
webSettings.setDatabaseEnabled(true); // データベース有効化
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // キャッシュモード設定
webSettings.setAllowFileAccessFromFileURLs(true); // ファイルURLからのアクセス許可
webSettings.setAllowUniversalAccessFromFileURLs(true); // ユニバーサルアクセス許可
webSettings.setDatabaseEnabled(true); // データベース有効化
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // キャッシュモード設定
このコードブロックをポップアップで表示
User-Agent設定
String userAgent = webSettings.getUserAgentString();
webSettings.setUserAgentString(userAgent + " WebViewApp/1.0");
String userAgent = webSettings.getUserAgentString();
webSettings.setUserAgentString(userAgent + " WebViewApp/1.0");
このコードブロックをポップアップで表示
ワークスペースアクセス
URL構築
ワークスペースアクセスにはBase URLとAiTokenが必要です。
String baseUrl = "https://gptbots.ai/space/h5/home";
String aiToken = "YOUR_AI_TOKEN"; // 実際のAiTokenに置き換えてください
String fullUrl = baseUrl + "?AiToken=" + AiToken;
String baseUrl = "https://gptbots.ai/space/h5/home";
String aiToken = "YOUR_AI_TOKEN"; // 実際のAiTokenに置き換えてください
String fullUrl = baseUrl + "?AiToken=" + AiToken;
このコードブロックをポップアップで表示
アプリにはデフォルトAiTokenが設定されています。変更する場合はログイン画面で入力してください。
ページ読み込み
webView.loadUrl(fullUrl);
webView.loadUrl(fullUrl);
このコードブロックをポップアップで表示
WebViewとネイティブの連携
JavaScriptインターフェース登録
webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");
webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");
このコードブロックをポップアップで表示
H5ページはグローバルオブジェクトagentWebBridge
経由でネイティブメソッドを呼び出せます。
権限処理
WebView権限リクエスト
H5ページが録音等の特殊権限を要求する場合、WebViewの権限リクエストを処理します。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onPermissionRequest(PermissionRequest request) {
String[] requestedResources = request.getResources();
boolean hasAudioPermission = false;
for (String resource : requestedResources) {
if (PermissionRequest.RESOURCE_AUDIO_CAPTURE.equals(resource)) {
hasAudioPermission = true;
break;
}
}
if (hasAudioPermission) {
// アプリが録音権限を持っているか確認
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
request.grant(requestedResources);
} else {
// システム権限リクエスト
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE);
// 権限リクエストを保存し、取得後に処理
pendingPermissionRequest = request;
}
} else {
// その他権限は直接許可
request.grant(requestedResources);
}
}
});
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onPermissionRequest(PermissionRequest request) {
String[] requestedResources = request.getResources();
boolean hasAudioPermission = false;
for (String resource : requestedResources) {
if (PermissionRequest.RESOURCE_AUDIO_CAPTURE.equals(resource)) {
hasAudioPermission = true;
break;
}
}
if (hasAudioPermission) {
// アプリが録音権限を持っているか確認
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
request.grant(requestedResources);
} else {
// システム権限リクエスト
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE);
// 権限リクエストを保存し、取得後に処理
pendingPermissionRequest = request;
}
} else {
// その他権限は直接許可
request.grant(requestedResources);
}
}
});
このコードブロックをポップアップで表示
ファイル選択処理
H5ページのファイル選択操作を処理します。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// コールバック保存
this.filePathCallback = filePathCallback;
// ファイル選択Intent生成
Intent intent = fileChooserParams.createIntent();
startActivityForResult(intent, REQUEST_FILE_CHOOSER);
return true;
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_FILE_CHOOSER) {
if (filePathCallback != null) {
Uri[] results = null;
if (resultCode == RESULT_OK && data != null) {
// 選択結果を処理
// ...
}
filePathCallback.onReceiveValue(results);
filePathCallback = null;
}
}
}
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// コールバック保存
this.filePathCallback = filePathCallback;
// ファイル選択Intent生成
Intent intent = fileChooserParams.createIntent();
startActivityForResult(intent, REQUEST_FILE_CHOOSER);
return true;
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_FILE_CHOOSER) {
if (filePathCallback != null) {
Uri[] results = null;
if (resultCode == RESULT_OK && data != null) {
// 選択結果を処理
// ...
}
filePathCallback.onReceiveValue(results);
filePathCallback = null;
}
}
}
このコードブロックをポップアップで表示
機能例
WebViewの閉じる
H5ページからWebViewを閉じるリクエスト例:
var message = {
eventType: "click",
data: {
value: "close"
}
};
agentWebBridge.callNative(JSON.stringify(message));
var message = {
eventType: "click",
data: {
value: "close"
}
};
agentWebBridge.callNative(JSON.stringify(message));
このコードブロックをポップアップで表示
ネイティブ側の処理:
public void onClick(JSONObject data) {
String value = data.optString("value");
if (TextUtils.equals(value, "close")) {
closeWeb(data);
}
}
public void closeWeb(JSONObject data) {
// H5に閉じる通知
JSONObject willCloseData = new JSONObject();
willCloseData.put("value", data.optString("value"));
willCloseData.put("reason", "user_request");
willCloseData.put("delay", 1000);
willCloseData.put("timestamp", System.currentTimeMillis());
webViewBridge.callH5(WebViewBridge.EVENT_CLICK, willCloseData);
// 1秒後にActivityを終了
webView.postDelayed(() -> {
finish();
}, 1000);
}
public void onClick(JSONObject data) {
String value = data.optString("value");
if (TextUtils.equals(value, "close")) {
closeWeb(data);
}
}
public void closeWeb(JSONObject data) {
// H5に閉じる通知
JSONObject willCloseData = new JSONObject();
willCloseData.put("value", data.optString("value"));
willCloseData.put("reason", "user_request");
willCloseData.put("delay", 1000);
willCloseData.put("timestamp", System.currentTimeMillis());
webViewBridge.callH5(WebViewBridge.EVENT_CLICK, willCloseData);
// 1秒後にActivityを終了
webView.postDelayed(() -> {
finish();
}, 1000);
}
このコードブロックをポップアップで表示