# インストールとネイティブ環境の設定

React Native、Expo、HarmonyOSの構成に合わせてSDKを導入し、更新を読み込めるReleaseビルドを作成します。

## 環境を準備する {#prerequisites}

- すでにビルドされている React Native、Expo、または RNOH プロジェクト。特に明記されていない限り、コマンドは `package.json` を含む **アプリ ルート** から実行されます。
- Node.js ≥18.17 および既存のプラットフォーム ツールチェーン。 iOS ビルドには macOS が必要です。
- 個別のテスト アプリケーションとデバイス。 1 つのプラットフォームから始めます。

SDK ピアの依存関係では、React ≥16.8 および RN ≥0.59 が宣言されています。これは、すべてのバージョンおよびアーキテクチャに対するテストを保証するものではありません。プロジェクトのバージョンを維持し、以下のホスト構造に従ってください。

## SDK をインストールします {#install}

プロジェクトのタイプを選択します。 package.json を含むディレクトリでコマンドを実行します。

```bash group="Install" tab="React Native" title="React Native"
npm install -g rn-update-cli
npm install rn-update
```

```bash group="Install" tab="Expo" title="Expo"
npm install -g rn-update-cli
npx expo install rn-update
```

React Native の iOS プロジェクトでは、`ios` ディレクトリで（Bundler を使う場合は `bundle exec` を付けて）`pod install` を実行し、その後アプリのルートに戻ります。Expo は[ビルド手順](/docs/expo#build)の実行時にネイティブプロジェクトを生成します。ネイティブディレクトリがない場合は、先に `npx expo prebuild` を実行してください。

> [!WARNING] npm、yarn、pnpm を混合したり、複数のロックファイルをコミットしたりしないでください。チームのパッケージ マネージャーを 1 つ選択し、そのロックファイルを保持します。

> [!NOTE] `ios` または `android` での変更には、新しいネイティブ ビルドが必要です。 Metro 接続の開発アプリはリリース検証に代わるものではありません。

## サインインしてアプリケーションを作成または選択します {#app-config}

Pakta コンソールに登録し、アプリのルートからサインインします。

```bash title="App root"
pakta login
```

デフォルトでは、CLI はセッションを現在のディレクトリに `.pakta.token` として保存し、プロジェクトにすでに CLI 一時ディレクトリがある場合は `.pakta` を `.gitignore` に追加します。どちらのパスもコミットされていないことを確認します。パスワード、セッション ファイル、または `PAKTA_API_TOKEN` をリポジトリに置かないでください。 `RNU_SERVICE_URL` がセルフホステッド サービスを指す場合、資格情報はサービス URL ごとに個別に保存されます。

### アプリケーションを作成する

Android、iOS、HarmonyOS は別個のプラットフォーム アプリケーションです。必要に応じてそれぞれ作成します。 CLI は、新しく作成されたアプリケーションを選択し、それを `update.json` に書き込みます。

実際に出荷するプラットフォームの行のみを実行します。未使用のプラットフォーム アプリケーションを作成しないでください。

```bash
pakta createApp --platform android --name PaktaDemo
pakta createApp --platform ios --name PaktaDemo
pakta createApp --platform harmony --name PaktaDemo
```

名前は一致する可能性があります。プラットフォームは、構築するインストーラーと一致する必要があります。

### 既存のアプリケーションを選択します

アプリケーションがすでにコンソールに存在する場合は、プラットフォームのアプリケーションをリストし、1 つ選択します。

```bash
pakta apps --platform android
pakta selectApp --platform android
```

CLI には、アプリケーションとその `appId` が表示されます。使用する `appId` を入力します。これらのターゲットのプラットフォームを `ios` または `harmony` に置き換えます。 1 つの `update.json` で 3 つの選択をすべて保持できます。 1 つのプラットフォームを選択すると、他のエントリが保持されます。

### `appId`、`appKey`、`update.json` {#appkey}

選択後、アプリのルートには次のようなファイルが含まれます。

```json title="update.json"
{
  "android": {
    "appId": "YOUR_ANDROID_APP_ID",
    "appKey": "YOUR_ANDROID_APP_KEY"
  },
  "ios": {
    "appId": "YOUR_IOS_APP_ID",
    "appKey": "YOUR_IOS_APP_KEY"
  },
  "harmony": {
    "appId": "YOUR_HARMONY_APP_ID",
    "appKey": "YOUR_HARMONY_APP_KEY"
  }
}
```

実際のファイルには、作成または選択したプラットフォームのみが含まれます。従来のサービスは、`appId` 数値を書き込む場合があります。 Pakta スタンドアロン サービスは UUID を書き込む可能性があります。どちらもサーバーによって生成されたアプリケーション ID です。編集、並べ替え、変換しないでください。

|識別子 |センシティブ？ |用途 |
| --- | --- | --- |
| `appId` |いいえ | CLI、管理 API、ネイティブ パッケージの登録 |
| `appKey` |公開識別子 |アプリ内の`new Pakta({ appKey })` |
| `.pakta.token` |はい |ローカル CLI セッション。 `.gitignore` に保管してください |
| `PAKTA_API_TOKEN` |はい | CI / CLI パブリッシング。シークレットのみを介して挿入する |

`update.json` には公開資格情報が含まれていないため、チーム共有用にコミットできます。アプリケーション コードがそれをインポートすると、その内容は JavaScript バンドルに入ります。 CLI のみがそれを使用する場合、設定は公開されたままになります。プラットフォーム固有の `appKey` の読み込みについては、[ルート コンポーネント setup](/docs/integration#platform-key) を参照してください。

プロジェクトに一致するセクションのみに従ってください。

## Android: 接続バンドル読み込み {#android}

`MainApplication.kt` が `reactHost` および `getDefaultReactHost` を使用する場合は、既存のホストに `jsBundleFilePath` を追加します。

```kotlin title="MainApplication.kt · ReactHost"
import cn.reactnative.modules.update.UpdateContext

// Keep existing ReactHost, PackageList and getDefaultReactHost imports.
override val reactHost: ReactHost by lazy {
  getDefaultReactHost(
    context = applicationContext,
    packageList = PackageList(this).packages,
    jsBundleFilePath = UpdateContext.getBundleUrl(this),
  )
}
```

`DefaultReactNativeHost` / `ReactNativeHost` の場合、`UpdateContext` をインポートし、既存のホスト オブジェクトのメソッドをオーバーライドします。

```kotlin title="MainApplication.kt · ReactNativeHost"
override fun getJSBundleFile(): String? =
  UpdateContext.getBundleUrl(this@MainApplication)
```

既存のリリース設定で PNG クランチを無効にして、リソース バイトの差を減らします。

```groovy title="android/app/build.gradle"
android {
  buildTypes {
    release {
      crunchPngs false
    }
  }
}
```

自動リンクによってモジュールが接続され、SDK の Gradle 統合によってビルド ID が提供されます。 `buildTime` を発明しないでください。既存の署名とビルド設定を保持します。

[ルート コンポーネント ](/docs/integration) を接続し、`android` から `./gradlew assembleRelease` を実行するか、Windows では `.\gradlew.bat assembleRelease` を実行します。フレーバー付きプロジェクトには、一致するリリース タスクを使用します。

### Java プロジェクト {#android-java}

`android/app/src/main/java/your/package/MainApplication.java` を開きます。 `import cn.reactnative.modules.update.UpdateContext;` を先頭に追加し、このオーバーライドを既存の `ReactNativeHost` または `DefaultReactNativeHost` オブジェクト内に追加します。

```java title="MainApplication.java · inside the existing ReactNativeHost"
@Override
protected String getJSBundleFile() {
    return UpdateContext.getBundleUrl(MainApplication.this);
}
```

## iOS: リリース バンドルに Pakta を使用 {#ios}

`ios`: Bundler プロジェクトの場合は `bundle exec pod install`、それ以外の場合は `pod install` からポッドをインストールします。以下から RN テンプレートに一致するものを選択してください: RN 0.74+ は `bundleURL` を使用します。古いテンプレートは通常、`sourceURLForBridge:` を使用します。

```objc group="iOS bundle URL" tab="RN 0.74+" title="AppDelegate.mm · bundleURL"
#import "RCTPakta.h"

- (NSURL *)bundleURL
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [RCTPakta bundleURL];
#endif
}
```

```objc group="iOS bundle URL" tab="RN 0.73 and older" title="AppDelegate.mm · sourceURLForBridge"
#import "RCTPakta.h"

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [RCTPakta bundleURL];
#endif
}
```

既存のデバッグ エントリ ポイント、モジュール名、ライフサイクル メソッドを維持します。 Swift テンプレートでは、実際のリリース バンドル URL プロバイダーは `RCTPakta.bundleURL()` を返す必要があります。 AppDelegate 全体を置き換えるのではなく、プロジェクトの Objective-C ブリッジング ヘッダーを通じて `RCTPakta.h` を公開します。

[root](/docs/integration) に接続した後、Xcode で `.xcworkspace` を開き、署名とデバイスを選択し、リリース ビルドを確認します。登録用に同じアーカイブから IPA を保持します。

### Swift および古い AppDelegate テンプレート {#ios-swift}

`#import "RCTPakta.h"` をアプリターゲットの Objective-C ブリッジング ヘッダーに追加します。必要に応じて、そのヘッダーを作成し、[ビルド設定] → [Objective-C ブリッジング ヘッダー] で相対パス (`YourApp/YourApp-Bridging-Header.h` など) を設定します。

既存の URL プロバイダーを変更します。新しいテンプレートでは、このメソッドが `ReactNativeDelegate` 内に配置される場合があります。

```swift title="AppDelegate.swift · bundleURL"
override func bundleURL() -> URL? {
#if DEBUG
  return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
  return RCTPakta.bundleURL()
#endif
}
```

`sourceURLForBridge:` のみを含む古い Objective-C テンプレートの場合は、その署名を保持し、非 DEBUG ブランチで `[RCTPakta bundleURL]` を返します。混合ネイティブ アプリは、固定バンドル パスを使用してルート ビューを作成するのではなく、ブリッジ デリゲートを通じて URL を取得する必要があります。

## Expo: ネイティブモジュールを使ってビルドする {#expo}

Expo Go には、rn-update のネイティブ モジュールが含まれていません。次の手順に従います。

1. `npx expo install rn-update` を使用して **依存関係をインストール**します。カスタム チャネルの場合は、組み込みの構成プラグインを `expo.plugins` に追加します。
2. **ルート レイアウトを接続**: 既存の `Stack` / `Slot` を `app/_layout.tsx` で `UpdateProvider` でラップします。コンポーネントの外部にクライアントを作成します。
3. **ネイティブ アプリを構築します**: `npx expo run:android --variant release`、`npx expo run:ios --configuration Release`、または既存の EAS 運用プロファイルを実行します。
4. **インストールして確認**、Metro なしで起動します。その後、`bundle --expo` プラットフォーム `android` / `ios` を使用して OTA パッケージを作成します。

完全な手順については、[Expo ガイド ](/docs/expo) を参照してください。

## HarmonyOS: RNOH を統合する {#harmonyos}

HarmonyOS には、npm インストール以外に、HAR、ArkTS、および C++ の統合が必要です。これらの場所を例と比較してください。

|場所 |接続 |
| --- | --- |
| `harmony/entry/oh-package.json5` | Pakta HAR と RNOH の依存関係、パスを使用 |
| `harmony/entry/hvigorfile.ts` | SDK `harmony/hvigor-plugin` をインポートします。 `reactNativeUpdatePlugin()` をプラグインに追加 |
| `RNPackagesFactory.ets` | `PaktaPackage` をインポートし、RNPackage リストに追加します。
| `PackageProvider.cpp` / CMake | Pakta C++ パッケージとネイティブ リンケージを登録する |
| `pages/Index.ets` | `PaktaFileJSBundleProvider` を追加し、埋め込みフォールバックを保持します。

```bash title="App root"
pakta bundle --platform harmony --output .pakta/output/harmony.ppk --no-interactive
```

DevEco Studio でネイティブ `.app` を同期、署名、ビルドします。生成された raw ファイルのパスがホストと一致することを確認し、インストールして確認し、`uploadApp` に登録します。

完全なプロジェクトは [SDK サンプル ](https://github.com/pakta-team/rn-update/tree/main/Example): `testHotUpdate`、`expoUsePakta`、および `harmony_use_pakta`] にあります。リポジトリの相対パスを依存関係のパスに置き換えます。

### HarmonyOS ファイルの変更

これらのパスは、`harmony` と `node_modules` がアプリ ルート内の兄弟であることを前提としています。エントリを既存の依存関係、プラグイン、パッケージ リストにマージします。既存の登録をすべて保持します。 HAR、Hvigor プラグイン、ArkTS、および C++ の登録を追加し、リリース バンドル プロバイダーを設定します。

```json5 title="harmony/entry/oh-package.json5 · dependencies"
"pakta": "file:../../node_modules/rn-update/harmony/pakta.har"
```

```typescript title="harmony/entry/hvigorfile.ts"
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { reactNativeUpdatePlugin } from '../../node_modules/rn-update/harmony/hvigor-plugin';

export default {
  system: hapTasks,
  plugins: [reactNativeUpdatePlugin()],
};
```

```typescript title="harmony/entry/src/main/ets/RNPackagesFactory.ets"
import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';
import PaktaPackage from 'pakta';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [new PaktaPackage(ctx)];
}
```

```cmake title="harmony/entry/src/main/cpp/CMakeLists.txt · after add_library(rnoh_app ...)"
set(PAKTA_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules/rn-update/harmony/pakta/src/main/cpp")
target_include_directories(rnoh_app PRIVATE "${PAKTA_CPP_DIR}")
target_sources(rnoh_app PRIVATE "${PAKTA_CPP_DIR}/PaktaTurboModule.cpp")
```

```cpp title="harmony/entry/src/main/cpp/PackageProvider.cpp"
#include "RNOH/PackageProvider.h"
#include "PaktaPackage.h"
using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
  return {std::make_shared<PaktaPackage>(ctx)};
}
```

```typescript title="harmony/entry/src/main/ets/pages/Index.ets · imports"
import { PaktaFileJSBundleProvider } from 'pakta';
import { AnyJSBundleProvider, ResourceJSBundleProvider } from '@rnoh/react-native-openharmony';
```

```typescript title="Index.ets · RNApp jsBundleProvider"
jsBundleProvider: new AnyJSBundleProvider([
  new PaktaFileJSBundleProvider(this.rnohCoreContext.uiAbilityContext),
  new ResourceJSBundleProvider(
    this.rnohCoreContext.uiAbilityContext.resourceManager,
    'bundle.harmony.js'
  ),
]),
```

他の RNAApp プロパティを保持し、`rnohCoreContext` が準備されていることを確認します。リリース ビルドでは、埋め込みリソースの前に Pakta ファイルを試行する必要があり、その前に Metro プロバイダーはありません。

ルート レイアウトとチャンネル プラグインについては、[完全な Expo ガイド ](/docs/expo) を参照してください。

## セルフホスティング: SDK と CLI を個別に構成 {#self-host}

ホスト型サービスのユーザーはこのセクションをスキップできます。 SDK はパブリック更新 API を使用します。 CLI は管理エンドポイントを使用します。

```tsx title="Add to your existing Pakta options"
server: {
  main: ['https://YOUR_HOST/api'],
  queryUrls: ['https://YOUR_CDN/endpoints.json'],
},
```

ホストを展開アドレスに置き換えます。検出ファイルはデプロイメントに属している必要があります。サインインする前に CLI ホストを設定します。

```powershell title="PowerShell"
$env:RNU_SERVICE_URL = 'https://YOUR_HOST'
```

```bash title="Bash / zsh"
export RNU_SERVICE_URL=https://YOUR_HOST
```

## 手動リンク: 自動リンクが利用できない場合のみ {#manual-link}

React Native 0.60 以降は通常自動リンクします。 `npx react-native config` を実行して、rn-update の検出を確認し、iOS ポッドをインストールします。すでにリンクされている場合は、手動登録をスキップします。

古い Android プロジェクトには、Gradle 依存関係エントリと React パッケージ登録の両方が必要です。

```groovy title="android/settings.gradle"
include ':rn-update'
project(':rn-update').projectDir = new File(rootProject.projectDir, '../node_modules/rn-update/android')
```

```groovy title="android/app/build.gradle · dependencies"
implementation project(':rn-update')
```

`MainApplication.java` で、`new UpdatePackage()` を既存の `getPackages()` リストに追加してインポートします。

```java title="MainApplication.java"
import cn.reactnative.modules.update.UpdatePackage;

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
    new MainReactPackage(),
    new UpdatePackage()
  );
}
```

既存のパッケージをすべて保持し、`new UpdatePackage()` のみを追加します。 2 番目の React Host を作成しないでください。リンク後も、「Android バンドルのロード ](#android)」の説明に従って `UpdateContext.getBundleUrl(...)` を設定します。

iOS の検出が失敗した場合は、Podfile のアプリ ターゲット内に `pod 'rn-update', :path => '../node_modules/rn-update'` を追加し、pod install を実行します。リンクだけでは、上記のバンドル読み込みエントリは構成されません。

Pakta には、古い Xcode プロジェクトに直接組み込むための単独の `RCTPakta.xcodeproj` はありません。CocoaPods を使わない RN <0.60 の場合は、CocoaPods を導入するか、先に React Native をアップグレードしてください。手動で統合する場合は、アプリのターゲットに `ios/RCTPakta`、共有 C++ コア、`SSZipArchive` 依存関係、`pakta_build_time.txt` を含めます。その後、リリース版アプリの起動とネイティブパッケージの登録を確認してください。

## React-native-screens を使用した Android アクティビティの復元 {#android-activity}

React-native-screens を使用するアプリの場合は、MainActivity 復元構成を確認してください。以下には、RNScreensFragmentFactory を提供するバージョンが必要です。オーバーライドを MainActivityDelegate ではなく MainActivity に直接配置します。

```kotlin title="MainActivity.kt · imports and onCreate"
import android.os.Bundle
import com.swmansion.rnscreens.fragment.restoration.RNScreensFragmentFactory

override fun onCreate(savedInstanceState: Bundle?) {
  supportFragmentManager.fragmentFactory = RNScreensFragmentFactory()
  super.onCreate(savedInstanceState)
}
```

複製を追加するのではなく、既存の onCreate にマージします。このクラスのない古いリリースには、独自の [画面のインストール手順 ](https://github.com/software-mansion/react-native-screens#android)。

## オプション: ディープリンクからテスト更新を開く {#deep-link}

既存のスキャナー関数は[parseTestQrCode](/docs/api#function-parsetestqrcodeqrcode-string)です。ブラウザーやカメラからアプリを開けるようにするには、`paktademo` などの独自のスキームを設定してください。

既存の Android MainActivity アクティビティ内に別のフィルターを追加し、そのランチャー フィルターを保持し、 android:launchMode="singleTask" を使用します。

```xml title="AndroidManifest.xml · MainActivity"
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="paktademo" />
</intent-filter>
```

iOS の場合、アプリ ターゲットの [情報] → [URL タイプ] に paktademo を追加し、AppDelegate でアプリの React Native Linking 転送を保持します。 Expo は expo.scheme を使用します。ネイティブ インストーラーを再構築します。

テスト更新をアップロードした後、その完全なハッシュをコピーして、`paktademo://update?type=__rnPaktaVersionHash&data=ACTUAL_HASH` を開きます。プロバイダーはそれをチェックし、アプリのダウンロード/アクティベーションのフローに従います。 testChannel:false はテスト ペイロードを拒否します。

## Android AAB インストーラー {#aab}

実際に Google Play に送信された AAB を保持します。 `pakta parseAab PATH`で検査し、`pakta uploadAab PATH`で登録します。別のビルドの APK を置き換えないでください。

統合するためだけに、すべての言語、密度、ABI 分割を無効にしないでください。 Pakta CLI はデフォルトで `base` モジュールを抽出します。分散ビルドが追加の分割に依存する場合は、それらを明示的に選択します。

```bash title="Select AAB splits used by the distribution"
pakta uploadAab ./android/app/build/outputs/bundle/release/app-release.aab --splits config.xxhdpi,config.arm64_v8a
```

`--includeAllSplits` を使用して、すべてのスプリットを含む登録 APK を作成することもできます。分散ビルドを使用してリソースと更新を確認します。スプリットにアセットがない場合は、リソースのパッケージ化とネイティブ バージョンを調査します。

## 次のステップ {#verify}

依存関係がインストールされ、CLI が正しいプラットフォーム アプリケーションを選択し、ネイティブ ローディングが構成されます。 [app](/docs/integration) を接続し、バージョン パネルを追加して、ネイティブ パッケージをビルドします。

Local Expo のビルド フラグは、[公式 Expo CLI リファレンス ](https://docs.expo.dev/more/expo-cli/) に従います。
