diff --git a/README.md b/README.md index b2c19cc..afe91d1 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Guides on using the Pear Runtime to build and share P2P applications. * [Making a Pear Terminal Application](./guide/making-a-pear-terminal-app.md) * [Sharing a Pear Application](./guide/sharing-a-pear-app.md) * [Releasing a Pear Application](./guide/releasing-a-pear-app.md) +* [Making a Bare Mobile Application](./guide/making-a-bare-mobile-app.md) * [Creating a Pear Init Template](./guide/creating-a-pear-init-template.md) ### How-tos @@ -93,7 +94,6 @@ Applications built using Pear. ### Examples Collection of example applications that can be used as reference during development. -- [Cross-platform Pear App](./examples/cross-platform-pear-app.md): Cross-platform "Hello World" Pear application for Android and iOS. - [Bare on Mobile](./examples/bare-on-mobile.md): Reference applications for using Bare runtime on Android and iOS. - [React App using Pear](./examples/react-app-using-pear.md): Example application for building Pear applications using React framework. diff --git a/SUMMARY.md b/SUMMARY.md index 6dd61be..049346d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -23,6 +23,7 @@ * [Making a Pear Terminal Application](./guide/making-a-pear-terminal-app.md) * [Sharing a Pear Application](./guide/sharing-a-pear-app.md) * [Marking a Release](./guide/releasing-a-pear-app.md) +* [Making a Bare Mobile Application](./guide/making-a-bare-mobile-app.md) * [Debugging a Pear Terminal Application](./guide/debugging-a-pear-terminal-app.md) * [Creating a Pear Init Template](./guide/creating-a-pear-init-template.md) @@ -67,6 +68,5 @@ ### Examples -* [Cross-platform Pear App](examples/cross-platform-pear-app.md) * [Bare on Mobile](examples/bare-on-mobile.md) -* [React App using Pear](examples/react-app-using-pear.md) \ No newline at end of file +* [React App using Pear](examples/react-app-using-pear.md) diff --git a/assets/autopass-mobile-running.png b/assets/autopass-mobile-running.png new file mode 100644 index 0000000..51875fe Binary files /dev/null and b/assets/autopass-mobile-running.png differ diff --git a/examples/bare-on-mobile.md b/examples/bare-on-mobile.md index 904f3ba..ce6ec69 100644 --- a/examples/bare-on-mobile.md +++ b/examples/bare-on-mobile.md @@ -2,7 +2,7 @@ Bare can be embedded into mobile applications to serve as the "Pear-end" where the peer-to-peer code of the application is run. -To get started with embedding [Bare](../reference/bare/overview.md) into an [Expo](https://expo.dev/) mobile application use the [Bare on Expo](https://github.com/holepunchto/bare-expo) example as reference. This example integrates Bare as an isolated thread, called a worklet[^1], via [`react-native-bare-kit`](https://github.com/holepunchto/react-native-bare-kit). All code passed when starting the worklet will run in the Bare runtime and can be communicated with via an inter-process communication (IPC) stream. +To get started with [Bare](../reference/bare/overview.md) mobile development via [Expo](https://expo.dev/), check out the ["Making a Bare Mobile Application" guide](../guide/making-a-bare-mobile-app.md). It uses the [Bare on Expo](https://github.com/holepunchto/bare-expo) template to build a mobile app for syncing passwords with the [Pearpass desktop example](https://github.com/holepunchto/pearpass-example). This example integrates Bare as an isolated thread, called a worklet[^1], via [`react-native-bare-kit`](https://github.com/holepunchto/react-native-bare-kit). All code passed when starting the worklet will run in the Bare runtime and can be communicated with via an inter-process communication (IPC) stream. [^1]: This term was chosen to avoid ambiguity with worker threads as implemented by . diff --git a/examples/cross-platform-pear-app.md b/examples/cross-platform-pear-app.md deleted file mode 100644 index f5ffdcf..0000000 --- a/examples/cross-platform-pear-app.md +++ /dev/null @@ -1,9 +0,0 @@ -# Cross-platform Pear App - -A "Hello World" example of a cross-platform Pear application for Android and iOS using [Bare](https://github.com/holepunchto/bare) and [Expo SDK](https://expo.dev/). - -- [Pear Expo Hello World](https://github.com/holepunchto/pear-expo-hello-world) - -> This above example is still a work in progress, please expect further improvements. - -Note that on mobile, the React Native UI runs on one thread and the Bare local backend runs on another thread and they both communicate via an IPC API. \ No newline at end of file diff --git a/guide/making-a-bare-mobile-app.md b/guide/making-a-bare-mobile-app.md new file mode 100644 index 0000000..b882133 --- /dev/null +++ b/guide/making-a-bare-mobile-app.md @@ -0,0 +1,390 @@ +# Making a Bare Mobile Application + +This guide demonstrates how to build and run a mobile application using [Bare and Expo](https://github.com/holepunchto/bare-expo). + +We will be building an application that syncs data from the [Pearpass desktop application](https://github.com/holepunchto/pearpass-example/) using [autopass](https://github.com/holepunchto/autopass) and displaying a list of the passwords on mobile. + +## Project Dependencies + +1. Gradle version 8.10.2 +2. Java 23 +3. Android SDK (>= 28), NDK + +## Project Setup + +We will use the `bare-expo` template to build our application. To get started, first clone it with git in a new directory: + +```bash +git clone https://github.com/holepunchto/bare-expo.git autopass-mobile-example +``` + +Change to the project directory: + +```bash +cd autopass-mobile-example +``` + +And install the dependencies we will need: + +```bash +npm i b4a bare-fs bare-rpc corestore autopass @react-native-clipboard/clipboard +``` + +```bash +npm i bare-pack --save-dev +``` + +## Directory Structure + +`bare-expo` is a basic template for getting started with Bare applications on mobile. To build a "Pear-end", where the peer-to-peer (P2P) code of the application is run, we will change the directory structure a bit adding a dedicated directory for the Pear-end. + +Create a new directory called `backend`. This is where we will store our Pear-end code that will be run by Bare. + +```bash +mkdir backend +``` + +Create a new file `backend.mjs` in the `backend` directory, we will use this file as the entry point for anything P2P. All Bare code should be used here. + +```bash +touch backend/backend.mjs +``` + +Our React Native UI code will go in the existing `app/index.tsx` file. + +## Building the Application + +### Building the UI + +The `app/index.tsx` file that came with the `bare-expo` template serves as the entry point of the UI of the React Native app. + +Replace the contents of `app/index.tsx` with: + +```typescript +import React, { useState } from 'react' +import { + View, + Text, + TextInput, + Button, + FlatList, + Platform, + Alert, + StyleSheet +} from 'react-native' +import Clipboard from '@react-native-clipboard/clipboard' +import { Worklet } from 'react-native-bare-kit' +import bundle from './app.bundle' +import RPC from 'bare-rpc' +import b4a from 'b4a' + +type PasswordEntry = { + username: string + password: string + website: string +} + +export default function App() { + const [dataList, setDataList] = useState([]) + const [pairingInvite, setPairingInvite] = useState('') // State for pairing invite + const [isWorkletStarted, setIsWorkletStarted] = useState(false) // State to track worklet status + + const startWorklet = () => { + const worklet = new Worklet() + + // Correctly passing the args to worklet.start + worklet.start('/app.bundle', bundle, [Platform.OS, pairingInvite]) + const { IPC } = worklet + // Initialise RPC + new RPC(IPC, (req) => { + // Handle incoming RPC requests + + if (req.command === 'message') { + const data = b4a.toString(req.data) + const parsedData = JSON.parse(data) // Assuming data is a JSON string + const entry: PasswordEntry = { + username: parsedData[1], + password: parsedData[2], + website: parsedData[3] + } + // Update the dataList with the received entry + setDataList((prevDataList) => [...prevDataList, entry]) + } + + if (req.command === 'reset') { + setDataList(() => []) + } + }) + + setIsWorkletStarted(true) // Mark worklet as started + } + + const copyToClipboard = (item: PasswordEntry) => { + Clipboard.setString(item.password) // Copy password to clipboard + Alert.alert('Copied to Clipboard', item.password) + } + + return ( + + Autopass-example 🍐 + {!isWorkletStarted ? ( // Show input if worklet hasn't started + <> + +