Guía de instrucciones para la integración del espacio de trabajo en Android
Introducción
Esta guía explica en detalle cómo integrar el espacio de trabajo de GPTBots en aplicaciones Android, incluyendo la solicitud de permisos, la interacción entre el código nativo y H5, así como otras configuraciones relacionadas.
GPTBots también ofrece un proyecto DEMO del espacio de trabajo que puede ayudarle a comenzar rápidamente. Proyecto DEMO para Android: android-webview-bridge
Lista de permisos
Permisos básicos
Para garantizar que las funciones relacionadas con el espacio de trabajo estén disponibles con normalidad, debe configurar los siguientes permisos en 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" />
Gestión de permisos
Para asegurar que la aplicación pueda acceder correctamente al micrófono, la cámara, la galería y otros permisos sensibles en tiempo de ejecución, la aplicación debe solicitar dinámicamente los permisos de tiempo de ejecución necesarios al iniciarse:
// 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
};
Configuración de WebView
Configuración básica
La APP crea una instancia de WebView y realiza los ajustes necesarios:
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); // 不需要用户手势即可播放媒体
Configuración relacionada con la grabación de audio
webSettings.setAllowFileAccessFromFileURLs(true); // 允许文件 URL 访问文件
webSettings.setAllowUniversalAccessFromFileURLs(true); // 允许通用访问
webSettings.setDatabaseEnabled(true); // 启用数据库
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // 设置缓存模式
Configuración de User-Agent
String userAgent = webSettings.getUserAgentString();
webSettings.setUserAgentString(userAgent + " WebViewApp/1.0");
Acceso al espacio de trabajo
Construcción de la URL
El acceso al espacio de trabajo requiere los parámetros Base URL y AiToken:
String baseUrl = "https://gptbots.ai/space/h5/home";
String aiToken = "YOUR_AI_TOKEN"; // 替换为实际的AiToken
String fullUrl = baseUrl + "?AiToken=" + aiToken;
El AiToken predeterminado ya viene preconfigurado en la aplicación; si necesita cambiarlo, puede introducirlo en la página de inicio de sesión.
Para conocer el método de generación del AiToken, consulte Cifrado de AiToken.
Carga de la página
webView.loadUrl(fullUrl);
Interacción entre WebView y el código nativo
Registro de la interfaz JavaScript
webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");
La página H5 invoca los métodos nativos a través del objeto global agentWebBridge.
Gestión de permisos
Solicitud de permisos de WebView
Cuando la página H5 solicita permisos especiales (como la grabación de audio), es necesario gestionar la solicitud de permisos de 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);
}
}
});
Gestión de la selección de archivos
Gestión de la operación de selección de archivos de la página 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;
}
}
}
Ejemplos de funcionalidad
Cierre del WebView
La página H5 puede solicitar el cierre del WebView de la siguiente manera:
var message = {
eventType: "click",
data: {
value: "close"
}
};
agentWebBridge.callNative(JSON.stringify(message));
Gestión en el lado nativo:
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);
}
