logo
การพัฒนา
ค้นหา
Android Workspace Integration Guide

Android Workspace Integration Guide

Introduction

This guide provides detailed instructions on how to integrate the GPTBots workspace into an Android application, including permission requests, native-H5 interaction, and other related configurations.

GPTBots also provides a workspace demo project to help you get started quickly. Android demo project: Android Demo Project

Permission List

Basic Permissions

To ensure workspace-related functions work properly, configure the following permissions in AndroidManifest.xml:

Permission Handling

To ensure the app can access sensitive permissions like microphone, camera, and gallery at runtime, necessary runtime permissions should be requested when the app starts:

// Permissions requested for Android 13 and above private final String[] permissionsForAndroid13 = { Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VIDEO }; // Permissions requested for below Android 13 private final String[] permissionsForBelowAndroid13 = { Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };
                      
                      // Permissions requested for Android 13 and above
private final String[] permissionsForAndroid13 = {
    Manifest.permission.RECORD_AUDIO,
    Manifest.permission.READ_MEDIA_IMAGES,
    Manifest.permission.READ_MEDIA_AUDIO,
    Manifest.permission.READ_MEDIA_VIDEO
};

// Permissions requested for below Android 13
private final String[] permissionsForBelowAndroid13 = {
    Manifest.permission.RECORD_AUDIO,
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
};

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

WebView Configuration

Basic Configuration

The app creates a WebView instance and performs necessary settings:

WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // Enable JavaScript webSettings.setDomStorageEnabled(true); // Enable DOM storage API webSettings.setAllowFileAccess(true); // Allow file access webSettings.setAllowContentAccess(true); // Allow content URL access webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); // Allow mixed content webSettings.setMediaPlaybackRequiresUserGesture(false); // Media playback does not require user gesture
                      
                      WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true); // Enable JavaScript
webSettings.setDomStorageEnabled(true); // Enable DOM storage API
webSettings.setAllowFileAccess(true); // Allow file access
webSettings.setAllowContentAccess(true); // Allow content URL access
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); // Allow mixed content
webSettings.setMediaPlaybackRequiresUserGesture(false); // Media playback does not require user gesture

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

Audio Recording Configuration

webSettings.setAllowFileAccessFromFileURLs(true); // Allow file URLs to access files webSettings.setAllowUniversalAccessFromFileURLs(true); // Allow universal access webSettings.setDatabaseEnabled(true); // Enable database webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // Set cache mode
                      
                      webSettings.setAllowFileAccessFromFileURLs(true); // Allow file URLs to access files
webSettings.setAllowUniversalAccessFromFileURLs(true); // Allow universal access
webSettings.setDatabaseEnabled(true); // Enable database
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // Set cache mode

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

User-Agent Setting

String userAgent = webSettings.getUserAgentString(); webSettings.setUserAgentString(userAgent + " WebViewApp/1.0"); `` ## Workspace Access ### URL Construction Workspace access requires Base URL and AiToken parameters: ```java String baseUrl = "https://gptbots.ai/space/h5/home"; String aiToken = "YOUR_AI_TOKEN"; // Replace with actual AiToken String fullUrl = baseUrl + "?AiToken=" + aiToken; The default AiToken is pre-configured in the app. If you need to change it, you can enter it on the login page. ### Page Loading webView.loadUrl(fullUrl); ## WebView and Native Interaction ### Register JavaScript Interface ```java webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");
                      
                      String userAgent = webSettings.getUserAgentString();
webSettings.setUserAgentString(userAgent + " WebViewApp/1.0");
``
## Workspace Access

### URL Construction

Workspace access requires Base URL and AiToken parameters:
```java
String baseUrl = "https://gptbots.ai/space/h5/home";
String aiToken = "YOUR_AI_TOKEN"; // Replace with actual AiToken
String fullUrl = baseUrl + "?AiToken=" + aiToken;

The default AiToken is pre-configured in the app. If you need to change it, you can enter it on the login page.

### Page Loading

webView.loadUrl(fullUrl);

## WebView and Native Interaction

### Register JavaScript Interface
```java
webView.addJavascriptInterface(new JSBridge(), "agentWebBridge");

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

The H5 page calls native methods through the global object agentWebBridge.

Permission Handling

WebView Permission Requests

When the H5 page requests special permissions (such as audio recording), WebView permission requests need to be handled:

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) { // Check if the app has audio recording permission if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { request.grant(requestedResources); } else { // Request system permission requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE); // Store permission request for handling after obtaining permission pendingPermissionRequest = request; } } else { // Grant other permissions directly 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) {
            // Check if the app has audio recording permission
            if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
                request.grant(requestedResources);
            } else {
                // Request system permission
                requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE);
                // Store permission request for handling after obtaining permission
                pendingPermissionRequest = request;
            }
        } else {
            // Grant other permissions directly
            request.grant(requestedResources);
        }
    }
});

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

File Selection Handling

Handle file selection operations from H5 pages:

webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { // Save callback this.filePathCallback = filePathCallback; // Create file selection 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) { // Process selection results // ... } filePathCallback.onReceiveValue(results); filePathCallback = null; } } }
                      
                      webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        // Save callback
        this.filePathCallback = filePathCallback;
        
        // Create file selection 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) {
                // Process selection results
                // ...
            }
            
            filePathCallback.onReceiveValue(results);
            filePathCallback = null;
        }
    }
}

                    
บล็อกโค้ดนี้ในหน้าต่างลอย

Function Examples

Closing WebView

The H5 page can request to close the WebView in the following way:

var message = { eventType: "click", data: { value: "close" } }; agentWebBridge.callNative(JSON.stringify(message)); Native side handling: public void onClick(JSONObject data) { String value = data.optString("value"); if (TextUtils.equals(value, "close")) { closeWeb(data); } } public void closeWeb(JSONObject data) { // Notify H5 that it will close 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); // Delay closing Activity webView.postDelayed(() -> { finish(); }, 1000); }
                      
                      var message = {
    eventType: "click",
    data: {
        value: "close"
    }
};
agentWebBridge.callNative(JSON.stringify(message));

Native side handling:

public void onClick(JSONObject data) {
    String value = data.optString("value");
    if (TextUtils.equals(value, "close")) {
        closeWeb(data);
    }
}
public void closeWeb(JSONObject data) {
    // Notify H5 that it will close
    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);
    // Delay closing Activity
    webView.postDelayed(() -> {
        finish();
    }, 1000);
}

                    
บล็อกโค้ดนี้ในหน้าต่างลอย