# Channels and rollouts

Understand native channel identity and control each channel and native version independently.

## Choose a setup {#before}

For one distribution, leave the channel unset and use `default`. Configure additional channels when stores or internal testers need separate updates.

This guide creates an Android `huawei` channel, writes it into the app, registers the resulting build, and publishes an update.

## What a channel does {#what-is-a-channel}

One application can release to 10% of eligible Huawei devices and 100% of eligible Xiaomi devices independently.

| Field | Example | Where to set it |
| --- | --- | --- |
| Display name | Huawei store | Console |
| Channel code | `huawei` | Console and native app; values must match |
| Native version | `1.0.0` | Android versionName / iOS app version |

## 1. Create the channel {#manage}

1. Sign in, open **Applications**, and enter the application.
2. Open **Channels** and choose **Create channel**.
3. Enter `huawei` as the code and a readable channel name.
4. Keep hot updates enabled and the option to ignore timestamp/fingerprint checks disabled. The native download URL can remain empty.
5. Save and confirm the channel appears.

Codes contain 1–64 lowercase letters, digits, dots, underscores or hyphens. They cannot be edited after creation. Do not create another `default` channel.

Alternatively, after selecting the app:

```bash
pakta createChannel --name huawei --code huawei
pakta channels --platform android
```

## 2. Configure the native app {#identity}

Follow your platform below. **The channel belongs to the installed native build. Neither `new Pakta()` nor an upload flag changes it. Rebuild and install after editing.**

### Android {#android}

In `android/app/src/main/AndroidManifest.xml`, add this inside the existing `<application>`. Keep its other attributes and activities.

```xml title="android/app/src/main/AndroidManifest.xml · inside application"
<meta-data android:name="channel" android:value="huawei" />
```

Build from the `android` directory:

```powershell title="Windows"
.\gradlew.bat assembleRelease
```

```bash title="macOS / Linux"
./gradlew assembleRelease
```

Without product flavors, the output is usually `android/app/build/outputs/apk/release/app-release.apk`. Install and keep that exact APK.

For existing flavors, use `${PAKTA_CHANNEL}` as the manifest value and set `manifestPlaceholders = [PAKTA_CHANNEL: "huawei"]` inside the relevant flavor in `android/app/build.gradle`. Supply a value for every flavor and run its Release build task.

### iOS {#ios}

Add these entries to the root `<dict>` in your **app target's** `ios/YourApp/Info.plist`:

```xml title="Info.plist · inside dict"
<key>channel</key>
<string>appstore</string>
```

For an automatically generated plist, add a String property named `channel`, valued `appstore`, under the app target's **Info → Custom iOS Target Properties**. Do not edit a Pod's plist.

Create `appstore` in the console. Archive again, export and retain the IPA, and install the corresponding build.

### HarmonyOS {#harmonyos}

After [native integration](/docs/getting-started#harmonyos), add `channel` to `harmony/entry/src/main/resources/rawfile/meta.json`:

```json title="harmony/entry/src/main/resources/rawfile/meta.json"
{
  "channel": "huawei"
}
```

Preserve existing fields. The SDK Hvigor plugin retains the channel and writes build time and version. Sign and rebuild the `.app` in DevEco Studio; install and retain it.

### Expo {#expo}

For manually maintained `android` / `ios` directories, follow the native instructions above. With Expo `prebuild` or EAS, add this entry to `expo.plugins`:

```json title="app.json · expo.plugins"
{
  "expo": {
    "plugins": [
      ["rn-update", { "channel": "huawei" }]
    ]
  }
}
```

The `channel` is written to Android manifest metadata and iOS `Info.plist`. Use separate build configurations for different platform channels. No plugin entry is needed for `default`. See the [Expo guide](/docs/expo#channel).

## 3. Inspect and upload the build {#verify}

From the application root:

```bash
pakta selectApp --platform android
pakta parseApk ./android/app/build/outputs/apk/release/app-release.apk
pakta uploadApk ./android/app/build/outputs/apk/release/app-release.apk --channel huawei
```

Verify the parsed channel and native version before uploading. `--channel` only checks the value. If it disagrees, fix native configuration and rebuild.

| Format | Inspect | Upload |
| --- | --- | --- |
| APK | `parseApk PATH` | `uploadApk PATH --channel huawei` |
| AAB | `parseAab PATH` | `uploadAab PATH --channel huawei` |
| IPA | `parseIpa PATH` | `uploadIpa PATH --channel appstore` |
| Harmony APP | `parseApp PATH` | `uploadApp PATH --channel huawei` |

Refresh **Native builds** in the console. The channel and version must appear before you can select them as a release target.

## 4. Publish to a channel {#targets}

[Build a `.ppk`](/docs/publish#bundle), then run:

```bash
pakta publish .pakta/output/android.ppk --platform android --name fix-001 --channel huawei --packageVersion 1.0.0 --rollout 10 --no-interactive
```

Replace `1.0.0` with the uploaded native version. Use 100% for an isolated test application; start production releases with a small percentage. For browser steps, see [console publishing](/docs/console#publish).

To release to several channels, create this file in the app root:

```json title="targets.json"
[
  { "channel": "huawei", "packageVersion": "1.0.0", "rollout": 10 },
  { "channel": "xiaomi", "packageVersion": "1.0.0", "rollout": 100 }
]
```

```bash
pakta publish .pakta/output/android.ppk --platform android --name fix-001 --targets targets.json --no-interactive
```

Both targets need registered native builds. Build and publish separately for Android, iOS and HarmonyOS.

## Adjust, stop and recover {#lifecycle}

Click a target's channel/version label on the update row, or open **Publish** to edit multiple targets. Preview and confirm every change.

- Stop one target with **Cancel release**.
- Stop a whole channel under **Channels → Configure**, turn off hot updates and save.
- Restore a stable historical package to the same channel and native version using **Roll back to full rollout**.

Stopping or reducing a rollout does not remove updates already installed. Recovery still requires device checks, downloads and activation. See [recovery steps](/docs/console#rollback).

## Internal testing {#practices}

Create `internal`, write it into a test build, and distribute that build to testers. Publish there first, verify, then release to production channels. Renaming a console channel does not move installed devices between channels.
