Mobile App Development

Apa Itu Chunked Upload & Smart Split-ABI Delivery? Rahasia Distribusi OTA Aplikasi Android Berukuran Besar

Rahmad Riskiadi Rahmad Riskiadi
23 Oktober 2026
28 Views
Apa Itu Chunked Upload & Smart Split-ABI Delivery? Rahasia Distribusi OTA Aplikasi Android Berukuran Besar

Dua Tembok Besar dalam Distribusi Aplikasi Android Mandiri (Self-Hosted OTA)

Ketika Anda membangun aplikasi Android kelas berat yang menyertakan mesin pemrosesan native di dalamnya—seperti engine multimedia FFmpeg, model kecerdasan buatan lokal (On-Device Edge AI / TensorFlow Lite), maupun pustaka kriptografi C/C++—ukuran berkas instalasi APK Universal (Fat APK) dapat dengan mudah membengkak hingga 130 MB sampai 200 MB.

Jika aplikasi tersebut didistribusikan secara mandiri (Self-Hosted Over-The-Air / OTA Update) melalui infrastruktur server Anda sendiri, Anda akan langsung berhadapan dengan dua tembok masalah teknis yang serius:

  1. Di Sisi Server Admin (Masalah Upload Berkas Besar): Saat Admin mencoba mengunggah rilis APK baru berukuran 135 MB melalui web browser, proses unggahan sering kali terputus di tengah jalan akibat request timeout, atau langsung ditolak mentah-mentah dengan pesan HTTP 413 Content Too Large oleh layanan Reverse Proxy seperti Cloudflare (Free & Pro Tier) yang membatasi ukuran maksimal satu paket upload sebesar 100 MB.
  2. Di Sisi Pengguna (Masalah Pemborosan Kuota & Memori): Memaksa pengguna smartphone untuk mengunduh APK Universal sebesar 135 MB setiap kali ada pembaruan versi—padahal lebih dari 60% isi di dalam berkas tersebut adalah kode mesin untuk jenis prosesor lain yang tidak pernah dipakai oleh ponsel mereka—adalah pemborosan kuota internet yang menurunkan rasio keberhasilan update.

Di Radevanka Project, kami memecahkan kedua tantangan infrastruktur ini secara simultan melalui penggabungan dua teknik rekayasa modern: Chunked Upload di sisi hulu (server ingestion) dan Smart Split-ABI Delivery di sisi hilir (client distribution). Mari kita bedah cara kerja keduanya secara mendalam.

1. Apa Itu Chunked Upload & Bagaimana Cara Kerjanya?

Secara tradisional, pengunggahan berkas pada formulir web bekerja dengan mengirimkan seluruh isi berkas dalam satu permintaan HTTP POST (multipart/form-data) tunggal. Jika berkas yang diunggah berukuran 140 MB, maka browser harus mempertahankan satu koneksi terbuka hingga seluruh 140 MB tersebut selesai transit melewati jaringan.

Chunked Upload mengubah paradigma tersebut secara total. Alih-alih mengirimkan satu bongkahan raksasa, browser (menggunakan pustaka JavaScript seperti Resumable.js atau FilePond) memotong berkas 140 MB tersebut secara matematis di memori client menjadi kepingan-kepingan biner kecil (chunks)—misalnya masing-masing berukuran 10 MB.

Keunggulan Arsitektur Chunked Upload:

  • Melewati Batas 100 MB Cloudflare Secara Legal & Aman: Karena berkas 140 MB dikirim dalam 14 permintaan HTTP berurutan yang masing-masing hanya berukuran 10 MB, setiap paket melenggang mulus melewati gerbang proxy Cloudflare dan Nginx tanpa memicu Error 413, serta tanpa perlu membuka celah keamanan dengan menaikkan client_max_body_size secara ekstrem di server.
  • Tahan Gangguan Jaringan (Fault-Tolerant & Resumable): Apabila koneksi internet Admin sempat terputus saat mengunggah potongan ke-11 dari 14, sistem tidak perlu mengulang dari 0 MB. Cukup kirimkan ulang potongan ke-11 yang gagal tersebut!
  • Indikator Progres Presisi Tinggi: Setiap kali satu kepingan 10 MB mendarat di server, backend Laravel menghitung persentase kepingan yang telah terkumpul dan mengirimkan respons JSON (misalnya {"done": 78, "status": true}) untuk memperbarui bilah progres (progress bar) secara real-time.

Contoh Implementasi Kode Chunked Upload di Laravel

Di sisi backend Laravel, kita dapat mengorkestrasi penerimaan dan penyatuan kembali (reassembly) potongan-potongan berkas tersebut menggunakan pustaka pion/laravel-chunk-upload. Berikut adalah contoh implementasi Controller ilustratif yang bersih dan aman:

<?php
  
  namespace App\Http\Controllers\Admin;
  
  use Illuminate\Http\Request;
  use Illuminate\Http\UploadedFile;
  use Illuminate\Http\JsonResponse;
  use App\Http\Controllers\Controller;
  use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
  use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
  
  class ReleasePackageUploadController extends Controller
  {
      public function uploadChunk(Request $request): JsonResponse
      {
          // 1. Inisialisasi penerima chunk berdasarkan protokol request (Resumable.js)
          $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
  
          if ($receiver->isUploaded() === false) {
              return response()->json(['error' => 'Tidak ada paket chunk yang diterima.'], 400);
          }
  
          // 2. Terima dan simpan kepingan chunk sementara di direktori temp
          $save = $receiver->receive();
  
          // 3. Jika seluruh kepingan (100%) sudah lengkap, satukan menjadi file APK utuh!
          if ($save->isFinished()) {
              return $this->finalizeMergedApk($save->getFile(), $request);
          }
  
          // 4. Jika masih dalam proses pengiriman chunk, kembalikan persentase progres
          $handler = $save->handler();
  
          return response()->json([
              'done'   => $handler->getPercentageDone(),
              'status' => true,
          ]);
      }
  
      protected function finalizeMergedApk(UploadedFile $mergedFile, Request $request): JsonResponse
      {
          $abiVariant = $request->input('abi_type', 'universal');
          $targetFileName = "app-release-{$abiVariant}.apk";
  
          // Ambil metadata sebelum berkas dipindahkan dari ruang sementara
          $fileSize = $mergedFile->getSize();
  
          // Pindahkan berkas utuh ke storage distribusi publik
          $mergedFile->storeAs('releases', $targetFileName, 'public');
  
          // Bersihkan sisa file sementara jika masih ada
          if (file_exists($mergedFile->getPathname())) {
              @unlink($mergedFile->getPathname());
          }
  
          return response()->json([
              'status'    => true,
              'file_name' => $targetFileName,
              'size_byte' => $fileSize,
              'url'       => asset("storage/releases/{$targetFileName}"),
          ]);
      }
  }
  

2. Apa Itu Smart Split-ABI Delivery?

Setelah masalah unggahan ke server terpecahkan dengan Chunked Upload, kini kita beralih ke masalah kedua: Bagaimana cara memangkas ukuran berkas APK yang harus diunduh oleh pengguna? Jawabannya terletak pada pemahaman mengenai ABI (Application Binary Interface).

Perangkat Android di seluruh dunia berjalan di atas arsitektur instruksi prosesor (CPU) yang berbeda-beda. Ketika aplikasi Flutter atau Android Native Anda menggunakan pustaka C/C++ (berkas .so di dalam folder jniLibs), kompilator wajib menyediakan terjemahan kode mesin untuk masing-masing jenis CPU:

  • arm64-v8a (ARM 64-bit): Arsitektur prosesor modern yang digunakan oleh lebih dari 85% smartphone Android masa kini.
  • armeabi-v7a (ARM 32-bit): Arsitektur untuk perangkat Android generasi lama atau perangkat entry-level hemat daya.
  • x86_64 (Intel / AMD 64-bit): Arsitektur yang digunakan pada PC berbasis Android, Chromebook, serta Android Emulator di komputer pengembang.
  • universal (Fat APK): Satu berkas gabungan yang menumpuk seluruh pustaka arm64-v8a, armeabi-v7a, dan x86_64 sekaligus di dalam satu kontainer APK.

Perbandingan Ukuran Berkas: Universal APK vs Split-ABI

Saat Anda memproduksi berkas rilis di Flutter menggunakan perintah Split-per-ABI:

# Perintah kompilasi Flutter untuk memecah APK berdasarkan arsitektur CPU
  flutter build apk --release --split-per-abi
  

Gradle tidak lagi menumpuk seluruh pustaka C/C++ ke dalam satu file, melainkan menghasilkan berkas spesifik yang jauh lebih ramping:

  • app-universal-release.apk: ~134 MB (Berisi seluruh pustaka CPU)
  • app-arm64-v8a-release.apk: ~51 MB (Hemat ~62% ukuran file!)
  • app-armeabi-v7a-release.apk: ~44 MB (Hemat ~67% ukuran file!)
  • app-x86_64-release.apk: ~53 MB (Khusus Emulator/Chromebook)

3. Orkestrasi Smart Auto-Detection antara Flutter & API Laravel

Konsep Smart Split-ABI Delivery yang kami rancang di Radevanka Project bekerja dengan menghubungkan keempat varian berkas di server Laravel dengan detektor perangkat keras otomatis di dalam aplikasi Flutter.

A. Penyediaan Metadata Ukuran & Endpoint Dinamis di Laravel

Pada endpoint pemeriksaan versi API Laravel, server mengecek ukuran masing-masing berkas ABI secara real-time dan menyediakan template URL yang fleksibel:

// Contoh Payload JSON pada Endpoint /api/app-version di Laravel
  return response()->json([
      'latest_version' => '3.2.0',
      'force_update'   => false,
      'download_url'   => 'https://api.domain-anda.com/releases/app-release-{abi}.apk',
      'apk_sizes'      => [
          'arm64-v8a'   => filesize(storage_path('app/public/releases/app-release-arm64-v8a.apk')),
          'armeabi-v7a' => filesize(storage_path('app/public/releases/app-release-armeabi-v7a.apk')),
          'x86_64'      => filesize(storage_path('app/public/releases/app-release-x86_64.apk')),
          'universal'   => filesize(storage_path('app/public/releases/app-release-universal.apk')),
      ],
  ]);
  

B. Deteksi Arsitektur CPU Otomatis di Aplikasi Flutter

Ketika aplikasi Flutter mendeteksi adanya versi baru dari server, aplikasi tidak langsung mengunduh versi universal. Sebaliknya, aplikasi membaca daftar instruksi CPU yang didukung oleh motherboard ponsel menggunakan pustaka device_info_plus, lalu mengganti placeholder {abi} secara cerdas:

import 'package:device_info_plus/device_info_plus.dart';
  
  Future<String> resolveOptimalApkUrl(String urlTemplate) async {
    final deviceInfo = DeviceInfoPlugin();
    final androidInfo = await deviceInfo.androidInfo;
  
    // Ambil arsitektur CPU utama (Primary ABI) dari perangkat pengguna
    final List<String> supportedAbis = androidInfo.supportedAbis;
    String selectedAbi = 'universal';
  
    if (supportedAbis.contains('arm64-v8a')) {
      selectedAbi = 'arm64-v8a';
    } else if (supportedAbis.contains('armeabi-v7a')) {
      selectedAbi = 'armeabi-v7a';
    } else if (supportedAbis.contains('x86_64')) {
      selectedAbi = 'x86_64';
    }
  
    // Ganti placeholder {abi} dengan arsitektur spesifik perangkat
    return urlTemplate.replaceAll('{abi}', selectedAbi);
  }
  

Hasilnya? Pengguna ponsel Android modern dengan chip Snapdragon atau MediaTek 64-bit secara otomatis hanya mengunduh berkas arm64-v8a berukuran ~51 MB, bukan berkas 134 MB. Proses pengunduhan pembaruan berlangsung lebih dari dua kali lipat lebih cepat, kegagalan unduh akibat koneksi terputus berkurang drastis, dan beban keluar (outbound bandwidth) pada server Anda ikut terpangkas hingga 60%!

Kesimpulan: Rekayasa Infrastruktur yang Memihak Pengguna

Kombinasi Chunked Upload dan Smart Split-ABI Delivery adalah bukti nyata bagaimana rekayasa perangkat lunak yang matang mampu menyulap keterbatasan infrastruktur menjadi pengalaman pengguna yang mulus. Admin tidak lagi dipusingkan oleh batasan upload 100 MB Cloudflare saat merilis versi baru, dan pengguna akhir dapat menikmati pembaruan aplikasi yang cepat serta hemat kuota.

Di Radevanka Project, setiap detail arsitektur yang kami bangun selalu berpedoman pada filosofi "Build with logic. Secure with discipline. Deliver with pride." Apabila Anda sedang merancang ekosistem aplikasi mobile lintas platform maupun sistem distribusi backend berskala tinggi, tim Radevanka Project siap membantu mewujudkan arsitektur terbaik untuk bisnis Anda. Hubungi kami untuk berkonsultasi!

Tags: Chunked Upload Split ABI Flutter Laravel OTA Update Cloudflare Radevanka Project

Bagikan