Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions payjoin-ffi/react-native/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Package + build outputs
node_modules/
lib/
artifacts/

# Compiled Rust static libraries (produced by `ubrn build ios`)
*.xcframework/

# Generated by uniffi-bindgen-react-native (native projects, C++ glue, TS bindings)
rust_modules/
cpp/
android/
ios/
*.podspec
src/generated/
src/index.tsx
src/Native*.ts
3 changes: 3 additions & 0 deletions payjoin-ffi/react-native/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
tabWidth: 4
}
68 changes: 68 additions & 0 deletions payjoin-ffi/react-native/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Contributing

Instructions for building and testing the React Native bindings locally.

## Prerequisites

This assumes you already have Rust and Node.js installed.

Native builds additionally require:

- **Android:** the Android NDK (set `ANDROID_NDK_HOME`) and
[`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk) (`cargo install cargo-ndk`).
- **iOS (macOS only):** Xcode and the iOS Rust targets (added automatically by
the build script when using rustup).

## Build Bindings

Follow these steps to clone the repository and build the bindings.

```shell
git clone https://github.com/payjoin/rust-payjoin.git
cd rust-payjoin/payjoin-ffi/react-native

# Clean out stale generated output
npm run clean
rm -rf node_modules

# Install package dependencies
npm install

# Build the native libraries and generate the Turbo Module bindings
bash ./scripts/generate_bindings.sh
```

The script builds Android for all ABIs and, on macOS, iOS for device and
simulator, then compiles the generated TypeScript with
[react-native-builder-bob](https://github.com/callstack/react-native-builder-bob).

## Testing

On-device tests require an example app (not yet included) plus an iOS simulator
or Android emulator. In a headless environment, typecheck the generated
bindings:

```shell
npm run typecheck
```

## Packaging

The published package ships the native build outputs (the iOS
`PayjoinRnFramework.xcframework`, the Android libraries, the generated
`cpp/` glue, and the podspec). These are gitignored and produced by
`scripts/generate_bindings.sh`. Build and pack the tarball with:

```shell
bash ./contrib/pack.sh
```

The script installs dependencies from the lockfile (`npm ci`), generates the
bindings, verifies the artifacts, and writes the tarball to `artifacts/`.
`generate_bindings.sh` builds the iOS artifacts only on macOS, so run this
from a macOS host; on Linux the artifact check aborts rather than shipping a
tarball with no iOS slice.

As a safety net, `prepack` runs `scripts/check_artifacts.sh` on every
`npm pack`/`npm publish`, so an ad-hoc pack that skipped the build fails
instead of shipping a broken tarball.
48 changes: 48 additions & 0 deletions payjoin-ffi/react-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Payjoin React Native Bindings

Welcome to the React Native language bindings for the [Payjoin Dev Kit](https://payjoindevkit.org/)!

These bindings compile `payjoin-ffi` to native libraries (an iOS static
framework and Android `.so`s) and expose them to React Native through a JSI
Turbo Module, generated by
[uniffi-bindgen-react-native](https://github.com/jhugman/uniffi-bindgen-react-native).

> [!NOTE]
> For web and Node.js environments, use the sibling
> [`payjoin` JavaScript bindings](../javascript) instead. React Native cannot
> run the WebAssembly build those bindings produce (Hermes has no
> `WebAssembly` support), which is why these native bindings exist.

## Requirements

These bindings are a JSI Turbo Module and require React Native's New
Architecture, which is the default on React Native 0.76 and later. On older
releases you must enable it yourself. Without the New Architecture the native
module fails to register and the import throws at startup.

## Usage

### Install

```shell
npm install payjoin-rn
```

### Import

```ts
import payjoinRn, { uniffiInitAsync } from "payjoin-rn";

// Initialize before usage. On native this is a no-op; it exists for parity
// with the web bindings, which load WebAssembly asynchronously.
await uniffiInitAsync();

// The bindings are namespaced on the default export.
const { payjoin } = payjoinRn;
```

## Building locally

See [CONTRIBUTING.md](./CONTRIBUTING.md).

Made with [uniffi-bindgen-react-native](https://github.com/jhugman/uniffi-bindgen-react-native)
32 changes: 32 additions & 0 deletions payjoin-ffi/react-native/contrib/pack.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail

# Build the production package and pack the npm tarball into artifacts/.
#
# Unlike the javascript sibling, whose tarball ships only platform-independent
# wasm + JS, this tarball ships prebuilt native artifacts (the iOS xcframework
# and Android libraries). generate_bindings.sh builds the iOS half only on
# macOS, so run this from a macOS host; check_artifacts.sh aborts otherwise.

# Build against the maintained lockfile instead of resolving the dependency
# graph fresh on every run. use_lockfile copies Cargo-recent.lock into place
# and restores the previous state when this script exits.
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
cd "$REPO_ROOT"
source contrib/lockfile.sh
use_lockfile Cargo-recent.lock

cd "$REPO_ROOT/payjoin-ffi/react-native"

echo "==> Installing React Native dependencies..."
npm ci

echo "==> Generating FFI bindings..."
bash ./scripts/generate_bindings.sh

# npm pack runs the prepack hook (scripts/check_artifacts.sh), which aborts
# if any native output is missing, so no separate verification step here.
echo "==> Packing npm tarball..."
rm -rf artifacts
mkdir -p artifacts
npm pack --pack-destination artifacts
24 changes: 24 additions & 0 deletions payjoin-ffi/react-native/contrib/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

# Build against the maintained lockfile instead of resolving the dependency
# graph fresh on every run. use_lockfile copies Cargo-recent.lock into place
# and restores the previous state when this script exits.
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
cd "$REPO_ROOT"
source contrib/lockfile.sh
use_lockfile Cargo-recent.lock

cd "$REPO_ROOT/payjoin-ffi/react-native"

echo "==> Installing React Native dependencies..."
npm ci

echo "==> Generating FFI bindings..."
bash ./scripts/generate_bindings.sh

# On-device/simulator tests require the (deferred) example app plus an iOS
# simulator or Android emulator. Until then, typechecking the generated
# bindings is the strongest signal we can produce in a headless environment.
echo "==> Typechecking bindings..."
npm run typecheck
Loading
Loading