본문 건너뛰기

Capacitor에서 사용하는 커스텀 SQLite 확장 방법

Capacitor 앱에서 사용자 정의 SQLite 확장 로드: iOS 및 Android 제한, C 확장으로 빌드하는 방법 및 각 연결에 등록하는 방법.

Article Credits

마틴 도나디유

작가

발레리아

리뷰어

조던

편집자

Capacitor에서 사용자 정의 SQLite 확장 사용하기

Capacitor 앱에서 사용자 정의 SQLite 확장을 사용할 수 있지만, native code으로만 컴파일되어야 합니다. iOS에서는 확장을 정적으로 링크하고 각 연결에서 init 함수를 호출하고, Android에서는 CPU 아키텍처에 따라 확장을 native 라이브러리로 배포하고 SQLite 빌드를 로드할 수 있도록 합니다. 이 안내서에서는 플랫폼 간의 차이점을 설명하고 C로 작성된 실제 확장을 제공하며, iOS 및 Android에서 native 변경 사항을 설명합니다. @capgo/capacitor-fast-sql Capacitor 8.

사용자 정의 SQLite 확장을 사용하기 전에 C를 작성하기 전에 실제로 필요로 하는지 확인하세요. 많은 “확장”은 이미 내장되어 있습니다.

SQLite 확장 프로그램이란 무엇인가요?

확장 프로그램은 SQLite 연결에 새로운 것을 등록하는 네이티브 code입니다: 스칼라 함수 (haversine_km(...)), 집계 함수, 정렬 순서, 가상 테이블 및 FTS5 토큰화기. 모든 확장 프로그램은 하나의 진입점을 노출합니다:

int sqlite3_<name>_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);

SQLite는 연결당 한 번씩 호출합니다. 등록한 모든 항목은 해당 연결에만 존재합니다.

모바일 앱에서 일반적인 이유로 작성하는 경우:

  • 어떤 언어에서 기본 unicode61 토큰화기가 잘 처리하지 못하는 경우에 사용자 정의 FTS5 토큰화기를 작성합니다.
  • 필요한 수학 또는 지리 함수를 WHERE 와 ORDER BY (거리 정렬, 점수),
  • 사용자가 기대하는 방식으로 이름을 정렬하는 정렬 순서를 작성합니다.
  • 장치 내에서 검색을 위한 벡터 검색 확장 프로그램을 작성합니다.

기존에 구축된 것을 확인하세요

가장 오래된 iOS 및 Android 버전을 지원하는 플러그인에서 다음을 실행하세요:

import { FastSQL } from '@capgo/capacitor-fast-sql';

const db = await FastSQL.connect({ database: 'probe' });

const [{ v }] = await db.query('SELECT sqlite_version() AS v');
const options = await db.query('PRAGMA compile_options');
const functions = await db.query('SELECT name FROM pragma_function_list ORDER BY name');

console.log(v, options.map((r) => r.compile_options));

확장자가 필요하지 않은 경우가 많습니다:

필요 내장 기능 확인
JSON 열에 포함 JSON 함수 (json_extract, ->>) SQLite 3.38부터 내장 기능입니다. 오래된 Android 시스템 SQLite는 그들을 지원하지 않을 수 있습니다
전체 텍스트 검색 FTS4, FTS5 ENABLE_FTS4 / ENABLE_FTS5 in compile_options
공간 경계 박스 R*Tree ENABLE_RTREE
sin, cos, sqrt, pow 수학 함수 ENABLE_MATH_FUNCTIONS, SQLite 3.35+

모든 대상에서 이 기능이 존재한다면 여기서 멈춰라. Fast SQL의 웹 빌드는 공식 SQLite Wasm을 사용하며, JSON, FTS5 및 수학 함수를 포함한다.

iOS와 Android이 다르게 작동하는 이유

iOS. 시스템 libsqlite3 iOS의 SQLITE_OMIT_LOAD_EXTENSION, so load_extension() 애플 스토어 규칙도 새로운 code (지침 2.5.2)를 다운로드하고 실행하는 것을 금지하기 때문에 code를 로드하는 것은 불가능합니다. .dylib 을 다운로드하고 실행하는 것을 금지하고 있기 때문에 런타임에 sqlite3_auto_extension() 출시와 동시에 사용하지 마세요. iOS SDK에서 Xcode와 함께 배포되는 SDK에서 사용하지 마세요. sqlite3.h 를 사용하여 선언합니다. API_DEPRECATED("Process-global auto extensions are not supported on Apple platforms", ...)의 신뢰할 수 있는 방법은 연결 핸들을 열린 직후에 init 함수를 호출하는 것입니다.

Android. 안드로이드 프레임워크 내부의 SQLite (android.database.sqlite)에는 API를 로드하는 방법이 없습니다. 앱에 포함된 SQLite 빌드가 필요합니다. requery/sqlite-android 은 프레임워크 클래스의 대체품으로, FTS5 및 JSON을 포함한 최신 SQLite를 배포하고, 로드 가능한 __CAPGO_KEEP_0__를 지원합니다. SQLiteCustomExtensionYour extension becomes a .so 파일 하나당 ABI당 APK 내부에 __CAPGO_KEEP_0__가 됩니다.

Web. 기본 SQLite Wasm 빌드는 네이티브 code를 로드할 수 없습니다. 사용자 정의 Wasm 빌드의 SQLite와 code를 컴파일한 code가 필요합니다.

현재 플러그인은 다음을 지원합니다.

iOS 안드로이드 웹
@capgo/capacitor-fast-sql 8.2 Hook이 필요하지 않습니다. 프레임워크 SQLite를 사용하여 패치가 필요합니다. SQLite Wasm
@capacitor-community/sqlite 8.1 loadExtension() API에서 선언되지만 네이티브로 구현되지 않습니다. 동일 구현되지 않음

현재, 확장 추가는 작은 네이티브 패치로 이루어집니다. 이는 포함된 변경이며 Bun에서 이를 설치 시에도 유지할 수 있습니다.

Step 1: 확장 작성하기

A distance function은 좋은 예시입니다: 유용하고, 독립적이며, 쉽게 검증할 수 있습니다. 이를 저장하세요. geo.c:

#include <math.h>
#include <stddef.h>
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1

static void haversine_km(sqlite3_context *ctx, int argc, sqlite3_value **argv) {
  (void)argc;
  for (int i = 0; i < 4; i++) {
    if (sqlite3_value_type(argv[i]) == SQLITE_NULL) {
      sqlite3_result_null(ctx);
      return;
    }
  }
  const double earth_radius_km = 6371.0088;
  const double to_rad = M_PI / 180.0;
  double lat1 = sqlite3_value_double(argv[0]) * to_rad;
  double lon1 = sqlite3_value_double(argv[1]) * to_rad;
  double lat2 = sqlite3_value_double(argv[2]) * to_rad;
  double lon2 = sqlite3_value_double(argv[3]) * to_rad;
  double dlat = lat2 - lat1;
  double dlon = lon2 - lon1;
  double a = sin(dlat / 2) * sin(dlat / 2) +
             cos(lat1) * cos(lat2) * sin(dlon / 2) * sin(dlon / 2);
  sqlite3_result_double(ctx, 2 * earth_radius_km * asin(sqrt(a)));
}

int sqlite3_geo_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;
  return sqlite3_create_function_v2(
      db, "haversine_km", 4,
      SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS,
      NULL, haversine_km, NULL, NULL, NULL);
}

두 가지 방식으로 모두 빌드하는 동일한 파일입니다:

  • 로드 가능한 확장으로 (Android): SQLITE_EXTENSION_INIT1/2 route every SQLite call through the Capgo pApi 정적으로, .so (iOS): 매크로가 no-op이 되고 호출은 앱이 링크한 SQLite 라이브러리로 바로 가게 됩니다.
  • SQLite가 함수를 인덱스에 사용할 수 있도록 합니다. -DSQLITE_CORE 사용자 정의 함수를 안전하게 사용할 수 있도록 표시합니다.

SQLITE_DETERMINISTIC 사용자 정의 함수를 views와 triggers에서 사용할 수 있도록 표시합니다. SQLITE_INNOCUOUS 이 파일을 macOS에서 정적으로 빌드하고

정적으로 빌드한 경우 SQLite의 호출이 바로 SQLite 라이브러리로 가게 됩니다. -DSQLITE_CORE 그리고 호출 sqlite3_geo_init(db, NULL, NULL) 시스템 SQLite 연결에서 호출하고 load_extension로드 가능한 라이브러리로 호출하는

. 두 경우 모두 파리에서 런던까지 약 343.6 km로 반환합니다.

2단계: iOS, 앱으로 컴파일하고

  1. 페이지/영역: Capgo에 대한 페이지. 역할: UI 레이블. 표시되는 곳: about.astro에 대한 페이지. 메시지 키 `about_how_step_label` (About How Step Label). geo.c 앱 대상에 소스를 추가하십시오 App Xcode에서 App 으로 드래그하십시오
  2. 그룹으로 드래그하십시오 App/App-Bridging-Header.h 목표를 선택하십시오 Xcode는 브리징 헤더를 생성할 것을 제안합니다. 수락하거나, 생성하고.
  3. In 빌드 단계 > 컴파일 소스, 이중 클릭 geo.c 파일당 플래그를 추가하세요 -DSQLITE_CORE.

iOS SDK는 두 가지를 모두 배포합니다 sqlite3.h 및 sqlite3ext.h이러한 플러그인은 Fast SQL을 패치하여 열린 훅을 노출합니다

App-Bridging-Header.h:

#include <sqlite3.h>

int sqlite3_geo_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);

이 플러그인은 앱 내부에서 연결을 열어두기 때문에, 앱에서 설정할 수 있는 훅이 필요합니다

Bun는 의존성을 패치하고, 설치 시마다 패치를 재적용할 수 있습니다

bun patch @capgo/capacitor-fast-sql

수정 node_modules/@capgo/capacitor-fast-sql/ios/Sources/CapgoCapacitorFastSqlPlugin/SQLDatabase.swift.

public enum FastSqlExtensions {
    /// Called with every new connection handle right after it opens.
    /// Return SQLITE_OK (0) on success.
    public static var onOpen: ((OpaquePointer) -> Int32)?
}

그런 다음에 init(...)__CAPGO_KEEP_0__는 암호화 블록 뒤에 위치하고 try applyPerformanceOptions(...)이것을:

if let hook = FastSqlExtensions.onOpen {
    let rc = hook(db)
    if rc != SQLITE_OK {
        throw SQLError.openFailed(message: "Extension init failed with code \(rc)")
    }
}

패치 저장:

bun patch --commit node_modules/@capgo/capacitor-fast-sql

Bun는 파일을 patches/ __CAPGO_KEEP_0__를 package.json under patchedDependencies__CAPGO_KEEP_0__ 플러그인 패치 방법에 대한 Capacitor 플러그인 패치 방법에 대한 __CAPGO_KEEP_0__ 플러그인 패치 방법에 대한

__CAPGO_KEEP_0__ 플러그인 패치 방법에 대한

In ios/App/App/AppDelegate.swift__CAPGO_KEEP_0__ 플러그인 패치 방법에 대한 application(_:didFinishLaunchingWithOptions:):

import UIKit
import Capacitor
import CapgoCapacitorFastSql // CocoaPods module name. With SPM: import CapgoCapacitorFastSqlPlugin

// Inside the existing AppDelegate class:
func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FastSqlExtensions.onOpen = { db in
        sqlite3_geo_init(db, nil, nil)
    }
    return true
}

hook은 플러그인의 열린 경로 내에서 실행되므로, WebView 재로드 후에도 열린 모든 연결에 함수가 적용됩니다. 설정을 하면 JavaScript가 SQLCipher를 호출하기 전에 함수가 적용됩니다. didFinishLaunching guarantees는 JavaScript가 SQLCipher를 호출하기 전에 함수가 적용되도록 보장합니다. connect().

SQLCipher는 SQLite의 확장 함수를 빌드합니다. SQLCipher subspec을 사용하면 플러그인의 연결은 SQLCipher의 SQLite에 속합니다. -DSQLITE_CORE Step 3: Android, SQLite 확장 함수를 로드할 수 있는 SQLite를 번들링하세요.

Step 3: 안드로이드, 확장 기능을 로드할 수 있는 SQLite를 패키징하세요.

SQLite amalgamation

안드로이드 NDK를 설치해야 합니다 (안드로이드 스튜디오의 SDK 매니저에서 설치하세요). sqlite3ext.h plus sqlite3.h from the You need the Android NDK (install it from Android Studio’s __CAPGO_KEEP_0__ Manager) and plus from the SQLite amalgamation next to 다음에 geo.c.

export NDK=$HOME/Library/Android/sdk/ndk/<version>
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64   # linux-x86_64 on Linux
export API=24   # your minSdkVersion

for pair in \
  aarch64-linux-android:arm64-v8a \
  armv7a-linux-androideabi:armeabi-v7a \
  x86_64-linux-android:x86_64 \
  i686-linux-android:x86
do
  triple=${pair%%:*}
  abi=${pair##*:}
  mkdir -p android/app/src/main/jniLibs/$abi
  $TOOLCHAIN/bin/clang --target=$triple$API \
    -shared -fPIC -O2 \
    -Wl,-z,max-page-size=16384 \
    -o android/app/src/main/jniLibs/$abi/libgeo.so \
    geo.c -lm
done

-Wl,-z,max-page-size=16384 16 KB 페이지 크기와 __CAPGO_KEEP_0__ 플러그인 16 KB 페이지 크기와 Capacitor 플러그인64비트 장치만 대상으로 하는 앱은 32비트 ABI를 생략할 수 있습니다.

이 라이브러리는 libgeo.so이 라이브러리는 sqlite3_geo_initC 함수와 일치하는 SQLite의 기본 진입점 이름입니다.

설치 시간에 네이티브 라이브러리를 추출합니다.

최근 Android Gradle Plugin 버전은 APK 내부에 압축되지 않은 파일을 유지합니다. .so SQLite는 파일 경로를 사용하여 확장성을 로드하므로 압축을 풀어달라고 요청합니다. android/app/build.gradle:

android {
    packaging {
        jniLibs {
            useLegacyPackaging = true
        }
    }
}

SQLite-Android에 requery를 추가합니다.

In android/build.gradle (루트)에서 JitPack을 추가합니다.

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

Patch Fast SQL을 사용하세요

같은 Bun 패치 세션을 열고bun patch @capgo/capacitor-fast-sql)을 열고 두 개의 파일을 편집하세요.

node_modules/@capgo/capacitor-fast-sql/android/build.gradle,에서 dependencies:

implementation 'com.github.requery:sqlite-android:3.49.0'

JitPack에서 레포지토리의 빌드된 최신 버전을 사용하세요.

node_modules/@capgo/capacitor-fast-sql/android/src/main/java/app/capgo/capacitor/fastsql/SQLDatabase.java: requery의 프레임워크 임포트를 교체하고 확장 기능을 사용하는 구성으로 열어보세요.

// Replace:
// import android.database.sqlite.SQLiteDatabase;
// import android.database.sqlite.SQLiteStatement;
import io.requery.android.database.sqlite.SQLiteCustomExtension;
import io.requery.android.database.sqlite.SQLiteDatabase;
import io.requery.android.database.sqlite.SQLiteDatabaseConfiguration;
import io.requery.android.database.sqlite.SQLiteStatement;

public class SQLDatabase implements DatabaseConnection {

    /** Set from MainActivity before the first connection opens. */
    public static final java.util.List<SQLiteCustomExtension> extensions =
        new java.util.concurrent.CopyOnWriteArrayList<>();

    private SQLiteDatabase db;
    private volatile boolean inTransaction = false;

    public SQLDatabase(String path, boolean walMode, boolean performancePresets) throws Exception {
        SQLiteDatabaseConfiguration config = new SQLiteDatabaseConfiguration(
            path, SQLiteDatabase.CREATE_IF_NECESSARY);
        config.customExtensions.addAll(extensions);
        this.db = SQLiteDatabase.openDatabase(config, null, null);
        SQLPerformanceConfig.apply(db::execSQL, walMode, performancePresets);
    }

    // ... the rest of the class stays as it is
}

requery의 클래스는 프레임워크 API (rawQuery, compileStatement, execSQL, 트랜잭션)과 일치하므로 나머지 파일은 변경하지 않습니다. android.database.Cursor 그대로 유지하세요. 패치를 커밋하세요. bun patch --commit node_modules/@capgo/capacitor-fast-sql.

이것은 암호화되지 않은 경로만 변경합니다. 암호화된 연결은 SQLCipher의 클래스를 사용하며 이 패치는 그것을 건드리지 않습니다.

MainActivity에서 확장 기능을 등록하세요

package com.example.app;

import android.os.Bundle;
import app.capgo.capacitor.fastsql.SQLDatabase;
import com.getcapacitor.BridgeActivity;
import io.requery.android.database.sqlite.SQLiteCustomExtension;

public class MainActivity extends BridgeActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        String path = getApplicationInfo().nativeLibraryDir + "/libgeo.so";
        SQLDatabase.extensions.add(new SQLiteCustomExtension(path, "sqlite3_geo_init"));
        super.onCreate(savedInstanceState);
    }
}

등록하기 전에 super.onCreate 리스트는 WebView가 JavaScript를 실행하기 전에 채워집니다.

Java 함수를 사용하여 Android

Java로 작성된 스칼라 함수만 필요하다면, requery는 NDK가 필요하지 않게 하나를 등록할 수 있습니다. 패치된 내부에서 생성자, 열기 후: SQLDatabase 이것은 C로 heavu 쿼리를 처리하는 것보다 느립니다. JNI를 건너 뛸 때마다 호출이 필요하기 때문입니다. 그러나 유지 관리가 훨씬 더 간단합니다. FTS5 토크나이저와 가상 테이블은 여전히 C가 필요합니다.

db.addFunction("haversine_km", 4, (args, result) -> {
    double r = 6371.0088;
    double lat1 = Math.toRadians(args.getDouble(0));
    double lat2 = Math.toRadians(args.getDouble(2));
    double dlat = lat2 - lat1;
    double dlon = Math.toRadians(args.getDouble(3) - args.getDouble(1));
    double a = Math.pow(Math.sin(dlat / 2), 2)
             + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon / 2), 2);
    result.set(2 * r * Math.asin(Math.sqrt(a)));
});

Step 4: JavaScript에서 사용하기

페이지/영역: Capgo에 대한 페이지. 역할: UI 레이블. 표시되는 곳: about.astro에 대한 페이지. 메시지 키 `about_how_step_label` (Capgo에 대한 방법 단계 레이블)

이후 bunx cap sync 자연 재생:

import { FastSQL } from '@capgo/capacitor-fast-sql';

const db = await FastSQL.connect({ database: 'places' });

await db.execute(`CREATE TABLE IF NOT EXISTS places (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  lat REAL NOT NULL,
  lon REAL NOT NULL
)`);

const nearby = await db.query(
  `SELECT id, name, haversine_km(?, ?, lat, lon) AS km
   FROM places
   WHERE lat BETWEEN ? AND ? AND lon BETWEEN ? AND ?
   ORDER BY km
   LIMIT 20`,
  [userLat, userLon, userLat - 0.5, userLat + 0.5, userLon - 0.7, userLon + 0.7],
);

The BETWEEN 을 사용하여 후보자를 좁히기 전에 함수가 정확한 거리를 계산하기 전에. (lat, lon) 웹에서 JavaScript로의 대체

웹에서 자바스크립트 fallback

웹 빌드에서는 C code을 로드할 수 없습니다. 따라서 이를 감지하고 대체하십시오:

import { Capacitor } from '@capacitor/core';

export const hasGeoExtension = Capacitor.isNativePlatform();

// On the web: query the bounding box, then sort in JS with the same formula.

커스텀 FTS5 토크나이저

FTS5 토크나이저를 등록하는 동일한 메커니즘입니다. 초기화 함수에서 fts5_api 포인터를 가져오십시오. SELECT fts5(?1) FTS5 문서에서 패턴을 가져오십시오.FTS5 토크나이저를 호출하십시오. xCreateTokenizerFTS5 토크나이저를 등록하는 두 가지 추가 요구 사항이 있습니다:

  • SQLite 라이브러리가 FTS5를 포함해야 합니다. requery의 빌드는 포함합니다. iOS에서 PRAGMA compile_options for ENABLE_FTS5.
  • 배송 및 유지 관리
CREATE VIRTUAL TABLE docs USING fts5(title, body, tokenize = 'my_tokenizer');

배송 및 유지 관리

  • 원본 빌드 필요. 확장, 패치 및 Gradle 변경은 원본입니다. 새로운 App Store 및 Play Store 빌드가 필요합니다. Capgo 빌드 클라우드에서 둘 다 빌드하고 서명할 수 있습니다. 2026년 4월부터 iOS 업로드는 Xcode 26 이상으로 빌드해야 합니다.
  • JavaScript는 여전히 빠르게 움직일 수 있습니다. SQL이 호출하는 haversine_km 웹 번들에 살고 있으며 실시간 업데이트, 만약에 원본 빌드에 확장 포함된 경우에만 배포할 수 있습니다. 사용자가 이전 버전의 바이너리를 실행할 수 있는지 확인하기 위해 원본 버전 체크를 사용합니다.
  • 플러그인 업그레이드. When you update Fast SQL, Bun re-applies the patch. If the patched lines moved, the install fails loudly instead of silently dropping your hook. Re-create the patch on the new version.

문제 해결

no such function: haversine_km iOS에서 동작합니다. 호크가 설정되지 않았거나 데이터베이스가 이미 열려있었습니다. connect()호크가 설정되지 않았거나 데이터베이스가 이미 열려있었습니다. didFinishLaunching 호크 내부 로그를 확인하여 호크가 호출되는지 확인하세요.

iOS에서 충돌합니다. sqlite3_geo_init iOS에서 동작합니다. -DSQLITE_CORE 파일이 존재하지 않습니다. 따라서 파일이 로드 가능한 확장으로 컴파일되었으며 포인터를 참조합니다. pApi 포인터는 여기에 있습니다. nil 파일당 컴파일 플래그를 Compile Sources에 추가하세요.

no such function Android에서 동작합니다. 수정된 SQLDatabase 아직도 임포트합니다. android.database.sqlite.SQLiteDatabase또는 확장 프로그램이 첫 번째 연결 후 목록에 추가되었다. SQLDatabase.extensions.size() 연결 시.

dlopen failed: library "…/libgeo.so" not found. 기기 ABI (대부분의 휴대폰은) arm64-v8a확장 프로그램이 없거나 네이티브 라이브러리가 추출되지 않았다. useLegacyPackaging Android Studio의 APK 분석기와

undefined symbol: sqlite3_geo_init. APK를 검사하고 SQLiteCustomExtension entry point 이름이 전달된 static.

C 함수와 일치하지 않거나 함수가 선언된 재구축하십시오 .so 리빌드하고 -Wl,-z,max-page-size=16384 파일을

최신 NDK와 함께 그리고 requery를 16 KB 정렬을 위한 빌드된 버전으로 업데이트한다. 정확히 확인하세요 geo.c 파일 tree 내에 있는 대상의 멤버인지 확인하세요 App 파일 tree 내에 있는 대상이 아닌 다른 대상이 있는지 확인하세요

개요

플랫폼 확장자가 앱에 어떻게 포함되는지 확장자가 등록되는 위치
iOS 앱에 컴파일되는 과정 -DSQLITE_CORE 플러그인 hook이 새로운 연결마다 호출되는 과정 sqlite3_geo_init Android
Android .so per ABI in jniLibs, SQLiteCustomExtension 연결이 열릴 때마다 읽기 목록
Web stock SQLite Wasm 자바스크립트 기본값

기본 기능을 확인하세요. 기본 기능이 제공되지 않는 경우 C로 작성하고, 네이티브 패치 크기를 작게 유지하고, 지원하는 가장 오래된 기기에서 테스트하세요. 일반적인 플러그인 설정은 Capacitor 앱에서 SQLite 사용 방법.

Live updates for Capacitor apps

웹-layer 버그가 활성화되면 Capgo을 통해 고치고 앱 스토어 승인 대기 시간을 기다리지 않습니다. 사용자는 배경에서 업데이트를 받으면서 네이티브 변경 사항은 일반적인 검토 경로를 유지합니다.

최신 뉴스

Capgo은 전문적인 모바일 앱을 만들기 위해 필요한 최고의洞察력을 제공합니다.