Belajar Capacitorjs - Menulis Custom Plugin (Swift + Kotlin)
Episode 12 of 28

Belajar Capacitorjs - Menulis Custom Plugin (Swift + Kotlin)

Membuat custom plugin Capacitor dari nol: bridge API dengan anotasi `@CAPPlugin` (Swift) dan `@CapacitorPlugin` (Kotlin), method invocation & callback, definisi TypeScript types, serta praktik plugin native sederhana yang dipakai dari JavaScript.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Setelah di episode 11 kita menguasai UI shell (splash screen, status bar, keyboard), pada episode ini kita naik level: menulis plugin native sendiri. Plugin custom adalah kekuatan sejati Capacitor — ketika plugin yang ada tidak memenuhi kebutuhan, kalian bisa menulis kode Swift dan Kotlin langsung dan memanggilnya dari JavaScript.

Mengapa menulis plugin sendiri? Karena ekosistem plugin tidak selalu lengkap. Beberapa kebutuhan spesifik — seperti integrasi SDK native tertentu, akses API hardware yang tidak didukung plugin resmi, atau optimasi performa untuk use case spesifik — membutuhkan kode native.

Struktur Plugin

Setiap plugin Capacitor terdiri dari:

  1. TypeScript definitions — interface dan class yang diekspor ke JavaScript.
  2. Kode Swift (iOS) — implementasi native untuk iOS.
  3. Kode Kotlin (Android) — implementasi native untuk Android.

Plugin di TypeScript

definitions.ts
import { registerPlugin } from '@capacitor/core';
 
export interface DeviceInfoPlugin {
  getDeviceInfo(): Promise<{
    model: string;
    systemVersion: string;
    batteryLevel: number;
  }>;
}
 
const DeviceInfo = registerPlugin<DeviceInfoPlugin>('DeviceInfo');
 
export default DeviceInfo;

Implementasi iOS (Swift)

Struktur File

plaintext
ios/App/App/DeviceInfoPlugin.swift

Kode Swift

DeviceInfoPlugin.swift
import Capacitor
 
@objc(DeviceInfoPlugin)
public class DeviceInfoPlugin: CAPPlugin {
    @objc func getDeviceInfo(_ call: CAPPluginCall) {
        let device = UIDevice.current
        let batteryLevel = device.batteryLevel
 
        call.resolve([
            "model": device.model,
            "systemVersion": device.systemVersion,
            "batteryLevel": batteryLevel >= 0 ? batteryLevel : 0,
        ])
    }
}

Penjelasan Anotasi

  • @objc(DeviceInfoPlugin) — mendaftarkan class ke Objective-C runtime agar bisa dipanggil oleh bridge.
  • CAPPlugin — base class dari semua plugin Capacitor di iOS.
  • @objc func — method harus menggunakan @objc agar bisa dipanggil dari bridge.
  • call.resolve(...) — mengembalikan success response ke JavaScript.
  • call.reject(...) — mengembalikan error ke JavaScript.

Mendaftarkan Plugin

Di AppDelegate.swift:

AppDelegate.swift
import Capacitor
 
@UIApplicationMain
class AppDelegate: CAPBridgingAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Plugin terdaftar otomatis jika file ada di target
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

Implementasi Android (Kotlin)

Struktur File

plaintext
android/app/src/main/java/com/example/app/DeviceInfoPlugin.kt

Kode Kotlin

KotlinDeviceInfoPlugin.kt
package com.example.app
 
import android.os.BatteryManager
import android.os.Build
import com.getcapacitor.JSObject
import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
 
@CapacitorPlugin(name = "DeviceInfo")
class DeviceInfoPlugin : Plugin() {
 
    @PluginMethod
    fun getDeviceInfo(call: PluginCall) {
        val batteryManager = context.getSystemService(BatteryManager::class.java)
        val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) / 100f
 
        val result = JSObject()
        result.put("model", Build.MODEL)
        result.put("systemVersion", Build.VERSION.RELEASE)
        result.put("batteryLevel", batteryLevel)
 
        call.resolve(result)
    }
}

Penjelasan Anotasi

  • @CapacitorPlugin(name = "DeviceInfo") — mendaftarkan plugin dengan nama yang cocok dengan TypeScript.
  • Plugin() — base class dari semua plugin Capacitor di Android.
  • @PluginMethod — menandai method sebagai callable dari JavaScript.
  • call.resolve(result) — mengembalikan success response.
  • call.reject("message") — mengembalikan error.

Mendaftarkan Plugin

Di MainActivity.java:

JavaMainActivity.java
package com.example.app;
 
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
 
public class MainActivity extends BridgeActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Daftarkan plugin custom
        this.bridge.registerPlugin(DeviceInfoPlugin.class);
        super.onCreate(savedInstanceState);
    }
}

Permission Handling Pattern

Jika plugin membutuhkan permission:

Permission handling (iOS)
@objc func checkPermission(_ call: CAPPluginCall) {
    let status = AVCaptureDevice.authorizationStatus(for: .video)
    switch status {
    case .authorized:
        call.resolve(["granted": true])
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video) { granted in
            call.resolve(["granted": granted])
        }
    default:
        call.resolve(["granted": false])
    }
}
KotlinPermission handling (Android)
@PluginMethod
fun checkPermission(call: PluginCall) {
    val granted = ContextCompat.checkSelfPermission(
        context, Manifest.permission.CAMERA
    ) == PackageManager.PERMISSION_GRANTED
    call.resolve(JSObject().put("granted", granted))
}

Testing Custom Plugin

Build dan jalankan
npm run build
npx cap sync
npx cap run ios

Di JavaScript:

Panggil plugin dari JS
import DeviceInfo from './definitions';
 
async function showDeviceInfo() {
  const info = await DeviceInfo.getDeviceInfo();
  console.log('Model:', info.model);
  console.log('OS:', info.systemVersion);
  console.log('Battery:', info.batteryLevel);
}

Tip

Untuk development, gunakan npx cap open ios atau npx cap open android untuk membuka project di IDE native. Debugging langsung di Xcode/Android Studio lebih cepat daripada console.log dari JavaScript.

Penutup

Pada episode 12 ini, kalian telah memahami:

  • Struktur plugin: TypeScript definitions + Swift (iOS) + Kotlin (Android).
  • Anotasi @CAPPlugin (Swift) dan @CapacitorPlugin (Kotlin) untuk registrasi.
  • Method invocation: call.resolve() untuk success, call.reject() untuk error.
  • Permission handling pattern untuk plugin yang membutuhkan akses hardware.

Di episode 13 selanjutnya, kita akan membahas kustomisasi proyek native — Info.plist permissions, AndroidManifest, Gradle dependencies, dan filosofi editing langsung proyek native sebagai source of truth. Sampai jumpa!

Belajar Capacitorjs - Menulis Custom Plugin (Swift + Kotlin) | Belajar Capacitorjs