Memahami masalah CORS di WebView, solusi CapacitorHttp yang mem-patch fetch/XHR ke native HTTP stack, cookie management, JSON handling otomatis, serta konsumsi API third-party tanpa server proxy.

Setelah di episode 9 kita menguasai Deep Links dan App State, pada episode ini kita membahas networking di Capacitor — topik yang sering menjadi sumber frustrasi bagi web developer yang pindah ke mobile. CORS yang tidak bisa di-disable, cookie yang tidak work, dan API yang tidak bisa diakses dari WebView adalah masalah umum.
Mengapa networking penting? Karena hampir semua aplikasi mobile membutuhkan API. Jika networking tidak berjalan lancar, aplikasi tidak akan bisa menampilkan data, mengirim form, atau berkomunikasi dengan server.
Di browser, CORS (Cross-Origin Resource Sharing) dikontrol oleh server — browser menolak response yang tidak punya header Access-Control-Allow-Origin. Di WebView, masalahnya lebih kompleks: tidak ada cara untuk "disable" CORS seperti di browser dev tools.
Ketika aplikasi web berjalan di WebView, request dari http://localhost ke https://api.example.com akan diblokir oleh CORS jika server tidak mengizinkan origin tersebut.
Capacitor 6+ memperkenalkan CapacitorHttp — fitur yang mem-patch global fetch dan XMLHttpRequest agar menggunakan native HTTP stack (NSURLSession di iOS, HttpURLConnection di Android) alih-alih WebView HTTP engine.
Artinya: CORS tidak berlaku karena request tidak lagi keluar dari WebView, melainkan dari kode native langsung.
const config: CapacitorConfig = {
// ...
plugins: {
CapacitorHttp: {
enabled: true, // aktifkan patch global
},
},
};Setelah diaktifkan, semua fetch() dan XMLHttpRequest secara otomatis menggunakan native HTTP stack.
Sebelum CapacitorHttp, banyak developer menggunakan Express proxy atau CORS proxy di server. Dengan CapacitorHttp, kalian bisa langsung mengkonsumsi API:
// Sebelum CapacitorHttp: perlu proxy server
// const response = await fetch('/api-proxy/external-api.com/data');
// Sesudah CapacitorHttp: langsung fetch
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);const response = await fetch('https://api.example.com/protected', {
credentials: 'include',
headers: {
Cookie: 'session=abc123; theme=dark',
},
});const response = await fetch('https://api.example.com/login', {
method: 'POST',
body: JSON.stringify({ username: 'user', password: 'pass' }),
});
const setCookie = response.headers.get('Set-Cookie');
console.log('Set-Cookie:', setCookie);Note
Dengan CapacitorHttp, cookie handling berjalan persis seperti di browser — termasuk cookie persisten dan SameSite attributes. Tidak perlu penanganan khusus.
CapacitorHttp otomatis mengenali Content-Type: application/json dan melakukan parse/stringify:
// Request JSON
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'test' }),
});
// Response otomatis ter-parse jika content-type JSON
const data = await response.json();Karena request berjalan di native HTTP stack, ada beberapa limitasi dibanding browser HTTP:
Untuk kebanyakan use case, ini bukan masalah. Streaming hanya diperlukan untuk file besar atau real-time data — yang bisa ditangani dengan WebSocket atau plugin native khusus.
async function fetchWithRetry(url: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error);
if (i === retries - 1) throw error;
// Tunggu sebelum retry
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
}
}
}Karena request berjalan di native HTTP stack, kalian mendapatkan beberapa keunggulan:
Tip
Untuk file besar (video, gambar high-res), pertimbangkan upload langsung ke cloud storage (S3, GCS) dengan pre-signed URL. CapacitorHttp sangat cocok untuk ini karena tidak ada batasan CORS.
Pada episode 10 ini, kalian telah memahami:
fetch dan XMLHttpRequest ke native HTTP stack.Di episode 11 selanjutnya, kita akan membahas Splash Screen, Status Bar, dan Keyboard — polish launch experience, styling status bar untuk dark mode, safe area insets, dan edge-to-edge layout. Sampai jumpa!