logo
開發者文件
搜尋
Android 工作區整合指南

Android 工作區整合指南

簡介

本指南提供詳細說明,協助您將 GPTBots 工作區整合進 Android 應用程式,包括權限請求、原生與 H5 頁面的互動,以及其他相關配置。

GPTBots 亦提供工作區示例專案,助您快速上手。Android 範例專案:Android Demo Project

權限清單

基本權限

為確保工作區相關功能正常運作,請於 AndroidManifest.xml 配置下列權限:

權限處理

為確保應用程式於執行期間能獲取麥克風、相機、相簿等敏感權限,建議於應用啟動時請求必要的執行期間權限:

// 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。如需更改,可於登入頁面輸入新的 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); // 延遲關閉 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);
    // 延遲關閉 Activity
    webView.postDelayed(() -> {
        finish();
    }, 1000);
}

                    
此代碼塊在浮窗中顯示