> ## Documentation Index
> Fetch the complete documentation index at: https://globaliptv.misidev.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Packaging

> How to generate a signed .pkg file for submission to the Roku Channel Store.

A signed `.pkg` file is required for every Roku Channel Store submission. The signing key is tied to your device's DevID — you generate it once per device using `genkey`.

<Warning>
  Never commit `SIGN_PASSWORD` to version control. Treat it the same as a password or API key. Add it to your shell profile or a local `.env` file that is listed in `.gitignore`.
</Warning>

## Prerequisites

* Roku device in developer mode (see [Sideloading](/build/sideloading))
* `make`, `zip`, `curl`, and `telnet` installed
* A signing key loaded on the device (generated in step 2 below)

## Steps

<Steps>
  <Step title="Confirm developer mode is active">
    The device must be in developer mode before you can generate a signing key or package the channel. If you have not done this yet, follow the [Sideloading guide](/build/sideloading) first.
  </Step>

  <Step title="Generate a signing key with genkey">
    Connect to the Roku's BrightScript console via Telnet:

    ```bash theme={null}
    telnet <ROKU_IP> 8080
    ```

    At the console prompt, run:

    ```text theme={null}
    genkey
    ```

    The device responds with output similar to:

    ```text theme={null}
    Password: abc123xyz
    DevID: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
    ```

    **Save both values immediately.** The `Password` is your `SIGN_PASSWORD`. The `DevID` identifies the signing key tied to this device.

    <Note>
      Each call to `genkey` creates a new key and invalidates the previous one. Any `.pkg` files signed with the old key cannot be re-signed; you would need to submit a new package. Generate the key once and keep the password safe.
    </Note>
  </Step>

  <Step title="Increment build_version in the manifest">
    The Roku Channel Store rejects a package with the same `build_version` as a previously submitted one. Before packaging for submission, open `manifest` and increment the value:

    ```text theme={null}
    build_version=8
    ```

    Current manifest values:

    ```text theme={null}
    major_version=1
    minor_version=0
    build_version=7
    ```

    <Note>
      Increment `build_version` for every Channel Store submission, even if `major_version` and `minor_version` are unchanged. Keep the value in `APP_VERSION` in the `Makefile` and `APP_VERSION` in `source/AppConstants.brs` aligned with the manifest.
    </Note>
  </Step>

  <Step title="Run make pkg">
    Run the packaging target with all three required variables:

    ```bash theme={null}
    make pkg ROKU_IP=192.168.1.42 ROKU_PASS=yourpassword SIGN_PASSWORD=abc123xyz
    ```

    The target:

    1. Builds `out/GlobalTV.zip`
    2. Sideloads the zip to the device
    3. Requests a signed package via `http://<ROKU_IP>/plugin_package`
    4. Downloads the `.pkg` from the device
  </Step>

  <Step title="Verify the output file">
    On success, the signed package is saved to:

    ```text theme={null}
    out/GlobalTV-1.0.6.pkg
    ```

    The console output confirms the path:

    ```text theme={null}
    >>> [pkg] OK → out/GlobalTV-1.0.6.pkg
    >>> [pkg] Listo para subir al Roku Channel Store.
    ```

    If the `.pkg` is not produced, the Makefile prints diagnostic steps:

    ```text theme={null}
    ERROR: No se pudo obtener el .pkg.
      → Verificá que SIGN_PASSWORD sea correcto.
      → Verificá que el Roku tenga una signing key (genkey).
      → Revisá http://<ROKU_IP>/plugin_package manualmente.
    ```
  </Step>

  <Step title="Submit to the Roku Channel Store">
    Log in to the [Roku Developer Portal](https://developer.roku.com) and navigate to **Manage Channels**. Select your channel and upload `out/GlobalTV-1.0.6.pkg` in the **Package submission** section.

    Run `make check` before submitting to catch any manifest or asset issues that would cause the submission to be rejected.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="ERROR: No se pudo obtener el .pkg">
    * Confirm `SIGN_PASSWORD` matches the password printed by `genkey`.
    * Confirm the device has a signing key (you ran `genkey` at least once on this device).
    * Open `http://<ROKU_IP>/plugin_package` in a browser while authenticated as `rokudev` to inspect the raw response.
  </Accordion>

  <Accordion title="Roku Channel Store rejects the package">
    * Ensure `build_version` in `manifest` is higher than the last submitted value.
    * Run `make check` and resolve all failures before re-packaging.
  </Accordion>

  <Accordion title="telnet: command not found (macOS)">
    Install telnet via Homebrew:

    ```bash theme={null}
    brew install telnet
    ```

    Alternatively, use `nc` (netcat):

    ```bash theme={null}
    nc <ROKU_IP> 8080
    ```
  </Accordion>
</AccordionGroup>
