Guide d'intégration de l'espace de travail côté Android
Introduction
Ce guide présente en détail comment intégrer l'espace de travail GPTBots dans une application Android, y compris la demande d'autorisations, l'interaction entre le natif et le H5 ainsi que d'autres configurations connexes.
GPTBots fournit également un projet de DÉMO pour l'espace de travail, qui peut vous aider à démarrer rapidement. Projet de DÉMO côté Android : android-webview-bridge
Liste des autorisations
Autorisations de base
Afin de garantir le bon fonctionnement des fonctionnalités liées à l'espace de travail, il est nécessaire de configurer les autorisations suivantes dans 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" />
Gestion des autorisations
Afin de garantir que l'application puisse accéder normalement à des autorisations sensibles telles que le microphone, l'appareil photo et la galerie lors de son exécution, l'application doit demander dynamiquement les autorisations d'exécution nécessaires à son démarrage :
// 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
};
Configuration de la WebView
Configuration de base
L'APP crée une instance de WebView et effectue les réglages nécessaires :
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); // 不需要用户手势即可播放媒体
Configuration relative à l'enregistrement audio
webSettings.setAllowFileAccessFromFileURLs(true); // 允许文件 URL 访问文件
webSettings.setAllowUniversalAccessFromFileURLs(true); // 允许通用访问
webSettings.setDatabaseEnabled(true); // 启用数据库
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // 设置缓存模式
Réglage du User-Agent
String userAgent = webSettings.getUserAgentString();
webSettings.setUserAgentString(userAgent + " WebViewApp/1.0");
Accès à l'espace de travail
Construction de l'URL
L'accès à l'espace de travail nécessite les paramètres Base URL et AiToken :
String baseUrl = "https://gptbots.ai/space/h5/home";
String aiToken = "YOUR_AI_TOKEN"; // 替换为实际的AiToken
String fullUrl = baseUrl + "?AiToken=" + aiToken;
L'AiToken par défaut est préconfiguré dans l'application ; si vous souhaitez le modifier, vous pouvez le saisir sur la page de connexion.
Pour la méthode de génération de l'AiToken, veuillez consulter Chiffrement de l'AiToken.
Chargement de la page
webView.loadUrl(fullUrl);
Interaction entre la WebView et le natif
Enregistrement de l'interface JavaScript
webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");
La page H5 appelle les méthodes natives via l'objet global agentWebBridge.
Gestion des autorisations
Demande d'autorisations de la WebView
Lorsque la page H5 demande des autorisations spéciales (telles que l'enregistrement audio), il est nécessaire de traiter la demande d'autorisation de la 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);
}
}
});
Gestion de la sélection de fichiers
Traiter l'opération de sélection de fichiers de la page 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;
}
}
}
Exemples de fonctionnalités
Fermeture de la WebView
La page H5 peut demander la fermeture de la WebView de la manière suivante :
var message = {
eventType: "click",
data: {
value: "close"
}
};
agentWebBridge.callNative(JSON.stringify(message));
Traitement côté natif :
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);
// 延迟关闭 Activity
webView.postDelayed(() -> {
finish();
}, 1000);
}
