Android Cloud Phone
The JS AIRA SDK provides a comprehensive solution for integrating Android cloud phone instances into web applications. This guide demonstrates how to implement real-time screen casting, device control, and interactive features.
Overview
Section titled “Overview”Android cloud phones offer virtualized mobile environments that can be controlled remotely through web browsers. The JS AIRA SDK enables developers to:
- Stream Android screens in real-time with high quality
- Control devices remotely including touch input, hardware buttons, and text input
- Handle multi-user scenarios with permission management
- Integrate seamlessly with modern web frameworks
Quick Integration Guide
Section titled “Quick Integration Guide”1. Installation
Section titled “1. Installation”Add the SDK script tag to your HTML file (before your application code):
<script src="https://unpkg.com/@agentbox-sdk/aira@2.16.2/dist/index.js"></script>2. Basic Setup
Section titled “2. Basic Setup”// Initialize SDK instance (using global variable from CDN)
const sdk = new window.NzCp();
// Configure connection parameters
const config = {
userId: 'unique-user-id', // Your user identifier
mountId: 'android-container', // DOM element ID for rendering
instanceNo: 'instance-id', // Instance number (required)
width: 720, // Screen width
height: 1280, // Screen height
bitrate: 2048, // Video quality
fps: 30 // Frame rate
};
// Set up event handlers
const callbacks = {
onStartSuccess: () => console.log('Connected to Android instance'),
onStartFail: (code) => console.error('Connection failed:', code),
onError: (code) => console.error('Runtime error:', code)
};
// Initialize and start
sdk.init(config, callbacks);
sdk.start('your-access-key', 'your-secret-key');3. Device Control
Section titled “3. Device Control”// Hardware button simulation
sdk.home(); // Home button
sdk.back(); // Back button
sdk.menu(); // Menu button
// Text input and clipboard
sdk.sendText('Hello World');
sdk.sendInClipper('Clipboard content');
// Cleanup when done
sdk.destroy();Framework Examples
Section titled “Framework Examples”<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Android Cloud Phone - AIRA SDK</title>
<script src="https://unpkg.com/@agentbox-sdk/aira@2.16.2/dist/index.js"></script>
<style>
body { margin: 0; font-family: Arial, sans-serif; }
#android-container { width: 100%; height: 100vh; background: #000; }
.controls {
position: fixed;
bottom: 20px;
left: 20px;
z-index: 1000;
background: rgba(0,0,0,0.7);
padding: 10px;
border-radius: 8px;
}
.controls button {
margin: 0 5px;
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.controls button:hover { background: #0056b3; }
.play-button {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 15px 30px;
font-size: 18px;
background: #28a745;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
</style>
</head>
<body>
<!-- Play button (shown before connection) -->
<button id="playBtn" class="play-button">Connect to Android</button>
<!-- Device controls (shown after connection) -->
<div id="controls" class="controls" style="display: none;">
<button id="backBtn">Back</button>
<button id="homeBtn">Home</button>
<button id="menuBtn">Menu</button>
<button id="stopBtn">Disconnect</button>
</div>
<!-- Android screen container -->
<div id="android-container"></div>
<script type="module">
class AndroidController {
constructor() {
this.sdk = null;
this.isConnected = false;
this.setupEventListeners();
}
setupEventListeners() {
document.getElementById('playBtn').addEventListener('click', () => this.connect());
document.getElementById('backBtn').addEventListener('click', () => this.pressBack());
document.getElementById('homeBtn').addEventListener('click', () => this.pressHome());
document.getElementById('menuBtn').addEventListener('click', () => this.pressMenu());
document.getElementById('stopBtn').addEventListener('click', () => this.disconnect());
}
async connect() {
try {
// Get credentials from your backend
const credentials = await this.getCredentials();
// Use global variable from CDN script tag
this.sdk = new window.NzCp();
const config = {
userId: 'user-123',
mountId: 'android-container',
instanceNo: 'instance-123',
width: 720,
height: 1280,
bitrate: 2048,
fps: 30
};
const callbacks = {
onStartSuccess: () => {
console.log('✅ Connected to Android instance');
this.onConnected();
},
onStartFail: (code) => {
console.error('❌ Connection failed:', code);
this.onConnectionFailed(code);
},
onError: (code) => {
console.error('⚠️ Runtime error:', code);
},
onStop: () => {
console.log('📱 Android session ended');
this.onDisconnected();
}
};
const initSuccess = this.sdk.init(config, callbacks);
if (!initSuccess) {
throw new Error('SDK initialization failed');
}
// Start the connection
this.sdk.start(credentials.accessKey, credentials.secretKey);
} catch (error) {
console.error('Connection error:', error);
alert('Failed to connect: ' + error.message);
}
}
async getCredentials() {
// Mock implementation for testing - Replace with your actual backend endpoint
// const response = await fetch('/api/instance/security-token', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'Platform-Access-Key': 'your-platform-key',
// 'Platform-Request-DateTime': Date.now().toString(),
// 'Platform-Request-Signature': 'calculated-signature'
// },
// body: JSON.stringify({
// userId: 'user-123',
// validTime: 3600
// })
// });
// if (!response.ok) {
// throw new Error('Failed to get credentials');
// }
// const result = await response.json();
// return {
// accessKey: result.data.accessKey,
// secretKey: result.data.accessSecretKey
// };
// Mock response for testing
return new Promise((resolve) => {
setTimeout(() => {
resolve({
accessKey: 'mock_access_key_' + Date.now(),
secretKey: 'mock_secret_key_' + Date.now()
});
}, 500); // Simulate network delay
});
}
onConnected() {
this.isConnected = true;
document.getElementById('playBtn').style.display = 'none';
document.getElementById('controls').style.display = 'block';
}
onConnectionFailed(code) {
alert(`Connection failed with error code: ${code}`);
}
onDisconnected() {
this.isConnected = false;
document.getElementById('playBtn').style.display = 'block';
document.getElementById('controls').style.display = 'none';
}
pressBack() {
if (this.sdk && this.isConnected) {
this.sdk.back();
}
}
pressHome() {
if (this.sdk && this.isConnected) {
this.sdk.home();
}
}
pressMenu() {
if (this.sdk && this.isConnected) {
this.sdk.menu();
}
}
disconnect() {
if (this.sdk) {
this.sdk.destroy();
this.sdk = null;
this.onDisconnected();
}
}
}
// Initialize the controller
new AndroidController();
</script>
</body>
</html><template>
<div class="android-integration">
<!-- Connection Button -->
<div v-if="!isConnected" class="connect-overlay">
<button
@click="connect"
:disabled="isConnecting"
class="connect-button"
>
{{ isConnecting ? 'Connecting...' : 'Connect to Android' }}
</button>
</div>
<!-- Device Controls -->
<div v-if="isConnected" class="device-controls">
<button @click="pressBack" class="control-btn">Back</button>
<button @click="pressHome" class="control-btn">Home</button>
<button @click="pressMenu" class="control-btn">Menu</button>
<button @click="sendText" class="control-btn">Text</button>
<button @click="disconnect" class="control-btn disconnect">Disconnect</button>
</div>
<!-- Android Screen Container -->
<div id="android-screen" class="android-screen"></div>
<!-- Status Display -->
<div v-if="status" class="status-bar" :class="statusType">
{{ status }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
// Note: Add SDK script tag to index.html:
// <script src="https://unpkg.com/@agentbox-sdk/aira@2.16.2/dist/index.js"></script>
// Reactive state
const isConnected = ref(false)
const isConnecting = ref(false)
const status = ref('')
const statusType = ref('info')
const sdk = ref(null)
// Lifecycle hooks
onMounted(() => {
console.log('Android integration component mounted')
})
onBeforeUnmount(() => {
if (sdk.value) {
sdk.value.destroy()
}
})
// Connection management
const connect = async () => {
try {
isConnecting.value = true
setStatus('Getting credentials...', 'info')
// Get credentials from your backend API
const credentials = await getCredentials()
setStatus('Initializing SDK...', 'info')
// Use global variable from CDN script tag
sdk.value = new window.NzCp()
const config = {
userId: 'user-123',
mountId: 'android-screen',
instanceNo: 'instance-123',
width: 720,
height: 1280,
bitrate: 2048,
fps: 30,
logLevel: 2
}
const callbacks = {
onStartSuccess: () => {
isConnected.value = true
isConnecting.value = false
setStatus('Connected successfully!', 'success')
console.log('✅ Android instance connected')
},
onStartFail: (code) => {
isConnecting.value = false
setStatus(`Connection failed: ${code}`, 'error')
console.error('❌ Connection failed:', code)
},
onError: (code) => {
setStatus(`Runtime error: ${code}`, 'error')
console.error('⚠️ Runtime error:', code)
},
onStop: () => {
handleDisconnection()
},
onPlayInfo: (info) => {
// Handle real-time streaming info
console.log('📊 Stream info:', info)
}
}
const initSuccess = sdk.value.init(config, callbacks)
if (!initSuccess) {
throw new Error('SDK initialization failed')
}
setStatus('Connecting to Android instance...', 'info')
sdk.value.start(credentials.accessKey, credentials.secretKey)
} catch (error) {
isConnecting.value = false
setStatus(`Error: ${error.message}`, 'error')
console.error('Connection error:', error)
}
}
const disconnect = () => {
if (sdk.value) {
sdk.value.destroy()
sdk.value = null
}
handleDisconnection()
}
const handleDisconnection = () => {
isConnected.value = false
isConnecting.value = false
setStatus('Disconnected', 'info')
}
// Device control methods
const pressBack = () => {
if (sdk.value && isConnected.value) {
sdk.value.back()
setStatus('Back button pressed', 'info')
}
}
const pressHome = () => {
if (sdk.value && isConnected.value) {
sdk.value.home()
setStatus('Home button pressed', 'info')
}
}
const pressMenu = () => {
if (sdk.value && isConnected.value) {
sdk.value.menu()
setStatus('Menu button pressed', 'info')
}
}
const sendText = () => {
if (sdk.value && isConnected.value) {
const text = prompt('Enter text to send:')
if (text) {
sdk.value.sendText(text)
setStatus(`Text sent: ${text}`, 'info')
}
}
}
// Helper functions
const setStatus = (message, type = 'info') => {
status.value = message
statusType.value = type
setTimeout(() => {
if (status.value === message) {
status.value = ''
}
}, 3000)
}
const getCredentials = async () => {
// Mock implementation for testing - Replace with your actual API endpoint
// const response = await fetch('/api/instance/security-token', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'Platform-Access-Key': 'your-platform-key',
// 'Platform-Request-DateTime': Date.now().toString(),
// 'Platform-Request-Signature': 'calculated-signature'
// },
// body: JSON.stringify({
// userId: `vue-user-${Date.now()}`,
// validTime: 3600
// })
// })
// if (!response.ok) {
// throw new Error('Failed to get credentials')
// }
// const result = await response.json()
// return {
// accessKey: result.data.accessKey,
// secretKey: result.data.accessSecretKey
// }
// Mock response for testing
return new Promise((resolve) => {
setTimeout(() => {
resolve({
accessKey: 'mock_access_key_' + Date.now(),
secretKey: 'mock_secret_key_' + Date.now()
});
}, 500); // Simulate network delay
});
}
</script>
<style scoped>
.android-integration {
position: relative;
width: 100%;
height: 100vh;
background: #1a1a1a;
overflow: hidden;
}
.connect-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.8);
z-index: 100;
}
.connect-button {
padding: 16px 32px;
font-size: 18px;
font-weight: 600;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.connect-button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.connect-button:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.device-controls {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
background: rgba(0, 0, 0, 0.8);
padding: 15px;
border-radius: 12px;
backdrop-filter: blur(10px);
z-index: 1000;
}
.control-btn {
padding: 10px 16px;
background: #4a5568;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
}
.control-btn:hover {
background: #5a6578;
transform: translateY(-1px);
}
.control-btn.disconnect {
background: #e53e3e;
}
.control-btn.disconnect:hover {
background: #f56565;
}
.android-screen {
width: 100%;
height: 100%;
background: #000;
}
.status-bar {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 16px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
z-index: 1000;
animation: slideIn 0.3s ease;
}
.status-bar.info {
background: #3182ce;
color: white;
}
.status-bar.success {
background: #38a169;
color: white;
}
.status-bar.error {
background: #e53e3e;
color: white;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
</style>import React, { useState, useEffect, useRef, useCallback } from 'react'
// Note: Add SDK script tag to index.html:
// <script src="https://unpkg.com/@agentbox-sdk/aira@2.16.2/dist/index.js"></script>
const AndroidIntegration = () => {
// State management
const [isConnected, setIsConnected] = useState(false)
const [isConnecting, setIsConnecting] = useState(false)
const [status, setStatus] = useState('')
const [statusType, setStatusType] = useState('info')
const sdkRef = useRef(null)
const statusTimeoutRef = useRef(null)
// Cleanup on unmount
useEffect(() => {
return () => {
if (sdkRef.current) {
sdkRef.current.destroy()
}
if (statusTimeoutRef.current) {
clearTimeout(statusTimeoutRef.current)
}
}
}, [])
// Status management
const updateStatus = useCallback((message, type = 'info') => {
setStatus(message)
setStatusType(type)
if (statusTimeoutRef.current) {
clearTimeout(statusTimeoutRef.current)
}
statusTimeoutRef.current = setTimeout(() => {
setStatus('')
}, 3000)
}, [])
// Get credentials from backend
const getCredentials = async () => {
// Mock implementation for testing - Replace with your actual API endpoint
// const response = await fetch('/api/instance/security-token', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'Platform-Access-Key': 'your-platform-key',
// 'Platform-Request-DateTime': Date.now().toString(),
// 'Platform-Request-Signature': 'calculated-signature'
// },
// body: JSON.stringify({
// userId: `react-user-${Date.now()}`,
// validTime: 3600
// })
// })
// if (!response.ok) {
// throw new Error(`HTTP ${response.status}: ${response.statusText}`)
// }
// const result = await response.json()
// return {
// accessKey: result.data.accessKey,
// secretKey: result.data.accessSecretKey
// }
// Mock response for testing
return new Promise((resolve) => {
setTimeout(() => {
resolve({
accessKey: 'mock_access_key_' + Date.now(),
secretKey: 'mock_secret_key_' + Date.now()
});
}, 500); // Simulate network delay
});
}
// Connection handlers
const handleConnection = useCallback(async () => {
try {
setIsConnecting(true)
updateStatus('Getting credentials...', 'info')
const credentials = await getCredentials()
updateStatus('Initializing SDK...', 'info')
// Use global variable from CDN script tag
const sdk = new window.NzCp()
sdkRef.current = sdk
const config = {
userId: 'user-123',
mountId: 'android-screen',
instanceNo: 'instance-123',
width: 720,
height: 1280,
bitrate: 2048,
fps: 30,
logLevel: 2
}
const callbacks = {
onStartSuccess: () => {
setIsConnected(true)
setIsConnecting(false)
updateStatus('Connected successfully!', 'success')
console.log('✅ Android instance connected')
},
onStartFail: (code) => {
setIsConnecting(false)
updateStatus(`Connection failed: Error ${code}`, 'error')
console.error('❌ Connection failed:', code)
},
onError: (code) => {
updateStatus(`Runtime error: ${code}`, 'error')
console.error('⚠️ Runtime error:', code)
},
onStop: () => {
handleDisconnection()
updateStatus('Connection stopped', 'info')
},
onPlayInfo: (info) => {
// Handle real-time streaming statistics
console.log('📊 Stream info:', info)
},
onRotationChange: (rotation) => {
console.log('🔄 Screen rotation changed:', rotation)
}
}
const initSuccess = sdk.init(config, callbacks)
if (!initSuccess) {
throw new Error('SDK initialization failed')
}
updateStatus('Connecting to Android instance...', 'info')
sdk.start(credentials.accessKey, credentials.secretKey)
} catch (error) {
setIsConnecting(false)
updateStatus(`Error: ${error.message}`, 'error')
console.error('❌ Connection error:', error)
}
}, [updateStatus])
const handleDisconnection = useCallback(() => {
if (sdkRef.current) {
sdkRef.current.destroy()
sdkRef.current = null
}
setIsConnected(false)
setIsConnecting(false)
}, [])
// Device control methods
const pressBack = useCallback(() => {
if (sdkRef.current && isConnected) {
sdkRef.current.back()
updateStatus('Back button pressed', 'info')
}
}, [isConnected, updateStatus])
const pressHome = useCallback(() => {
if (sdkRef.current && isConnected) {
sdkRef.current.home()
updateStatus('Home button pressed', 'info')
}
}, [isConnected, updateStatus])
const pressMenu = useCallback(() => {
if (sdkRef.current && isConnected) {
sdkRef.current.menu()
updateStatus('Menu button pressed', 'info')
}
}, [isConnected, updateStatus])
const sendText = useCallback(() => {
if (sdkRef.current && isConnected) {
const text = prompt('Enter text to send to Android device:')
if (text && text.trim()) {
sdkRef.current.sendText(text)
updateStatus(`Text sent: ${text}`, 'info')
}
}
}, [isConnected, updateStatus])
const takeScreenshot = useCallback(() => {
if (sdkRef.current && isConnected) {
// This is a placeholder - implement based on your SDK capabilities
updateStatus('Screenshot feature not implemented', 'info')
}
}, [isConnected, updateStatus])
return (
<div className="android-integration">
{/* Connection Overlay */}
{!isConnected && (
<div className="connect-overlay">
<button
onClick={handleConnection}
disabled={isConnecting}
className="connect-button"
>
{isConnecting ? 'Connecting...' : 'Connect to Android'}
</button>
</div>
)}
{/* Device Controls */}
{isConnected && (
<div className="device-controls">
<button onClick={pressBack} className="control-btn">
Back
</button>
<button onClick={pressHome} className="control-btn">
Home
</button>
<button onClick={pressMenu} className="control-btn">
Menu
</button>
<button onClick={sendText} className="control-btn">
Text
</button>
<button onClick={takeScreenshot} className="control-btn">
Screenshot
</button>
<button
onClick={handleDisconnection}
className="control-btn disconnect"
>
Disconnect
</button>
</div>
)}
{/* Android Screen Container */}
<div id="android-screen" className="android-screen" />
{/* Status Display */}
{status && (
<div className={`status-bar ${statusType}`}>
{status}
</div>
)}
<style jsx>{`
.android-integration {
position: relative;
width: 100%;
height: 100vh;
background: #1a1a1a;
overflow: hidden;
}
.connect-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.8);
z-index: 100;
}
.connect-button {
padding: 16px 32px;
font-size: 18px;
font-weight: 600;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.connect-button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.connect-button:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.device-controls {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
background: rgba(0, 0, 0, 0.8);
padding: 15px;
border-radius: 12px;
backdrop-filter: blur(10px);
z-index: 1000;
}
.control-btn {
padding: 10px 16px;
background: #4a5568;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
white-space: nowrap;
}
.control-btn:hover {
background: #5a6578;
transform: translateY(-1px);
}
.control-btn.disconnect {
background: #e53e3e;
}
.control-btn.disconnect:hover {
background: #f56565;
}
.android-screen {
width: 100%;
height: 100%;
background: #000;
}
.status-bar {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 16px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
z-index: 1000;
animation: slideIn 0.3s ease;
max-width: 300px;
}
.status-bar.info {
background: #3182ce;
color: white;
}
.status-bar.success {
background: #38a169;
color: white;
}
.status-bar.error {
background: #e53e3e;
color: white;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@media (max-width: 768px) {
.device-controls {
bottom: 10px;
left: 10px;
right: 10px;
transform: none;
flex-wrap: wrap;
justify-content: center;
}
.control-btn {
padding: 8px 12px;
font-size: 12px;
}
}
`}</style>
</div>
)
}
export default AndroidIntegrationBest Practices
Section titled “Best Practices”Security Considerations
Section titled “Security Considerations”Authentication API
Section titled “Authentication API”To get instance operation credentials, use the following API endpoint:
Endpoint: POST /api/instance/security-token
Content-Type: application/json
Description: Before using the SDK to operate instances, call this API with the user ID to get authentication credentials (accessKey/accessSecretKey), then pass them to the SDK for initialization. The SDK can only operate instances assigned to the specified user ID.
Request Headers:
| Name | Type | Required | Description |
|---|---|---|---|
Platform-Access-Key | string | ✓ | Platform access key |
Platform-Request-DateTime | string | ✓ | 13-digit timestamp of the request |
Platform-Request-Signature | string | ✓ | Calculated signature based on request parameters |
Request Body:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | ✓ | User ID - unique user identifier defined by your business logic. Can be a user’s unique identity or a timestamp-generated ID. SDK can only operate instances assigned to this user ID. |
validTime | int32 | ✗ | Credential validity duration in seconds (default: 3600/1 hour, minimum: 10 seconds) |
useOnce | boolean | ✗ | Whether credentials are single-use (default: false). If true, credentials become invalid after successful authentication |
instanceNos | array | ✗ | Array of instance IDs that can be operated. User can only operate instances in this list |
Response:
{
"data": {
"accessKey": "temp_access_key_here",
"accessSecretKey": "temp_secret_key_here",
"expireTime": "2024-11-07 15:30:00"
},
"code": 0,
"msg": "Success",
"times": 1699363800000
}Response Fields:
| Field | Type | Description |
|---|---|---|
data.accessKey | string | Temporary access key |
data.accessSecretKey | string | Temporary secret key |
data.expireTime | string | Expiration time (format: yyyy-MM-dd HH:mm:ss) |
code | int32 | Response code (0 = success, non-zero = error) |
msg | string | Response message |
times | int64 | Response timestamp |
Example Implementation:
// ❌ Don't do this - credentials exposed
const credentials = {
accessKey: 'your-key-here',
secretKey: 'your-secret-here'
};
// ✅ Do this - fetch from secure backend
async function getInstanceCredentials(userId) {
const response = await fetch('/api/instance/security-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Platform-Access-Key': 'your-platform-key',
'Platform-Request-DateTime': Date.now().toString(),
'Platform-Request-Signature': 'calculated-signature'
},
body: JSON.stringify({
userId: userId,
validTime: 3600, // 1 hour
useOnce: false
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (result.code !== 0) {
throw new Error(`API Error: ${result.msg}`);
}
return {
accessKey: result.data.accessKey,
secretKey: result.data.accessSecretKey,
expireTime: result.data.expireTime
};
}
// Use in your application
const credentials = await getInstanceCredentials('user-123');
sdk.start(credentials.accessKey, credentials.secretKey);Performance Optimization
Section titled “Performance Optimization”- Adjust bitrate based on network conditions (1-2 Mbps for mobile, 2-4 Mbps for desktop)
- Monitor stream quality using the
onPlayInfocallback - Implement reconnection logic for network interruptions
- Clean up resources when components unmount
Error Handling
Section titled “Error Handling”const callbacks = {
onStartFail: (code) => {
switch(code) {
case 60401002:
console.error('Invalid parameters - check configuration');
break;
case 60401003:
console.error('Network error - check connectivity');
break;
case 60100014:
console.error('Authentication failed - refresh credentials');
break;
default:
console.error(`Unknown error: ${code}`);
}
}
};Next Steps
Section titled “Next Steps”- Explore the complete AIRA SDK API Reference for advanced features
- Learn about multi-user collaboration capabilities
- Implement custom camera input for enhanced functionality
- Review error codes for comprehensive error handling