npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rozoai/deeplink-react-native

v0.0.1-beta.1

Published

React Native component for scanning QR codes with Expo

Downloads

97

Readme

@rozoai/deeplink-react-native

React Native QR code scanner component for Expo and Bare React Native apps. Automatically parses blockchain deeplinks using @rozoai/deeplink-core.

Features

  • 📱 Expo + Bare React Native support
  • 📷 Automatic camera permission handling
  • 🔍 QR code scanning using expo-camera
  • ⛓️ Multi-chain support: Ethereum, Solana, Stellar, and more
  • 🎨 Customizable UI with overlay and styling options
  • ♻️ Retry functionality with "Scan Again" button
  • 🔒 Type-safe with full TypeScript support

Installation

For Expo Projects

# Install the package
pnpm add @rozoai/deeplink-react-native @rozoai/deeplink-core

# Install Expo camera
npx expo install expo-camera

For Bare React Native Projects

# Install the package
pnpm add @rozoai/deeplink-react-native @rozoai/deeplink-core

# Install Expo camera
npx expo install expo-camera

# iOS only - install pods
cd ios && pod install && cd ..

Setup

Expo

No additional setup required for managed workflow. For bare workflow or custom development builds, see the expo-camera documentation.

Bare React Native

iOS (ios/Podfile)

# Already included if you ran pod install after expo install

Add to ios/YourApp/Info.plist:

<key>NSCameraUsageDescription</key>
<string>We need camera access to scan QR codes</string>

Android (android/app/src/main/AndroidManifest.xml)

<uses-permission android:name="android.permission.CAMERA" />

Usage

Basic Example

import React, { useState } from "react";
import { View, Button, Alert } from "react-native";
import { ScanQrNative } from "@rozoai/deeplink-react-native";
import { DeeplinkData } from "@rozoai/deeplink-core";

export default function App() {
  const [isScanning, setIsScanning] = useState(false);

  const handleScan = (data: DeeplinkData) => {
    console.log("Scanned data:", data);
    setIsScanning(false);

    // Handle different types
    switch (data.type) {
      case "ethereum":
        Alert.alert("Ethereum", `Address: ${data.address}`);
        break;
      case "solana":
        Alert.alert("Solana", `Address: ${data.address}`);
        break;
      case "stellar":
        Alert.alert("Stellar", `Address: ${data.address}`);
        break;
      case "website":
        Alert.alert("Website", `URL: ${data.url}`);
        break;
      default:
        Alert.alert("Scanned", JSON.stringify(data));
    }
  };

  const handleError = (error: Error) => {
    console.error("Scan error:", error);
    Alert.alert("Error", error.message);
    setIsScanning(false);
  };

  const handlePermissionDenied = () => {
    Alert.alert(
      "Permission Denied",
      "Please enable camera access in settings to scan QR codes."
    );
    setIsScanning(false);
  };

  return (
    <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <Button title="Scan QR Code" onPress={() => setIsScanning(true)} />

      <ScanQrNative
        isVisible={isScanning}
        onScan={handleScan}
        onError={handleError}
        onPermissionDenied={handlePermissionDenied}
      />
    </View>
  );
}

Advanced Example with Custom Styling

import { ScanQrNative } from "@rozoai/deeplink-react-native";

<ScanQrNative
  isVisible={isScanning}
  onScan={handleScan}
  onError={handleError}
  onPermissionDenied={handlePermissionDenied}
  headerText="Scan Crypto QR"
  instructionText="Align QR code within the frame"
  retryButtonText="Try Again"
  containerStyle={{
    backgroundColor: "#1a1a1a",
  }}
  overlayStyle={{
    backgroundColor: "rgba(0, 0, 0, 0.7)",
  }}
/>;

Full Example with Transaction Handling

import React, { useState } from "react";
import { View, Button, Text, StyleSheet } from "react-native";
import { ScanQrNative } from "@rozoai/deeplink-react-native";
import { DeeplinkData } from "@rozoai/deeplink-core";

export default function PaymentScreen() {
  const [isScanning, setIsScanning] = useState(false);
  const [scannedData, setScannedData] = useState<DeeplinkData | null>(null);

  const handleScan = (data: DeeplinkData) => {
    setScannedData(data);
    setIsScanning(false);

    // Process payment based on blockchain type
    if (data.type === "ethereum") {
      processEthereumPayment(data);
    } else if (data.type === "solana") {
      processSolanaPayment(data);
    } else if (data.type === "stellar") {
      processStellarPayment(data);
    }
  };

  const processEthereumPayment = (data: DeeplinkData) => {
    console.log("Processing Ethereum payment:", {
      to: data.address,
      amount: data.amount,
      chainId: data.chain_id,
      token: data.asset?.contract,
    });
    // Your Ethereum transaction logic here
  };

  const processSolanaPayment = (data: DeeplinkData) => {
    console.log("Processing Solana payment:", {
      to: data.address,
      amount: data.amount,
      splToken: data.asset?.contract,
    });
    // Your Solana transaction logic here
  };

  const processStellarPayment = (data: DeeplinkData) => {
    console.log("Processing Stellar payment:", {
      destination: data.address,
      amount: data.amount,
      asset: data.asset,
    });
    // Your Stellar transaction logic here
  };

  return (
    <View style={styles.container}>
      <Button title="Scan Payment QR" onPress={() => setIsScanning(true)} />

      {scannedData && (
        <View style={styles.resultContainer}>
          <Text style={styles.resultText}>Type: {scannedData.type}</Text>
          <Text style={styles.resultText}>Address: {scannedData.address}</Text>
          {scannedData.amount && (
            <Text style={styles.resultText}>Amount: {scannedData.amount}</Text>
          )}
        </View>
      )}

      <ScanQrNative
        isVisible={isScanning}
        onScan={handleScan}
        onError={(error) => console.error(error)}
        onPermissionDenied={() => setIsScanning(false)}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    padding: 20,
  },
  resultContainer: {
    marginTop: 20,
    padding: 15,
    backgroundColor: "#f0f0f0",
    borderRadius: 8,
  },
  resultText: {
    fontSize: 14,
    marginBottom: 5,
  },
});

API Reference

Props

| Prop | Type | Required | Default | Description | | -------------------- | ------------------------------ | -------- | ------------------------------------- | --------------------------------------------------- | | onScan | (data: DeeplinkData) => void | ✅ | - | Callback when QR is successfully scanned and parsed | | onError | (error: Error) => void | ✅ | - | Callback when an error occurs | | isVisible | boolean | ❌ | true | Controls scanner modal visibility | | onPermissionDenied | () => void | ❌ | - | Callback when camera permission is denied | | containerStyle | object | ❌ | - | Custom style for the main container | | overlayStyle | object | ❌ | - | Custom style for the scanner overlay | | headerText | string | ❌ | "Scan QR Code" | Header text displayed at the top | | instructionText | string | ❌ | "Position QR code within the frame" | Instruction text below scanner | | retryButtonText | string | ❌ | "Scan Again" | Text for the retry button |

DeeplinkData Type

The onScan callback receives a DeeplinkData object from @rozoai/deeplink-core:

type DeeplinkData =
  | EthereumParseResult
  | SolanaParseResult
  | StellarParseResult
  | WebsiteParseResult
  | AddressParseResult;

// Common fields across blockchain types
interface BlockchainParseResult {
  type: "ethereum" | "solana" | "stellar" | "address";
  address?: string;
  amount?: string;
  operation?: string;
  message: string;
  asset?: {
    contract?: string;
    code?: string;
    issuer?: string;
  };
  chain_id?: string | number;
  // ... and more fields
}

For full type definitions, see @rozoai/deeplink-core documentation.

Supported QR Code Formats

This library supports scanning and parsing:

  • Ethereum/EVM: EIP-681 payment requests, addresses
  • Solana: Solana Pay URIs, addresses
  • Stellar: SEP-7 payment URIs, addresses
  • Websites: HTTP/HTTPS URLs

For detailed format specifications, see QRSpec.md.

Troubleshooting

Camera Permission Issues

Problem: Camera permission is denied

Solution:

  1. Check that you've added camera usage descriptions to your app config
  2. Ensure the user hasn't permanently denied permission in device settings
  3. Use the onPermissionDenied callback to guide users to settings

Scanner Not Working in Expo Go

Problem: Scanner doesn't work in Expo Go app

Solution:

  • Expo Go supports expo-camera out of the box
  • Make sure you're using the latest version of Expo Go (SDK 51+)
  • If issues persist, create a development build: npx expo run:ios or npx expo run:android

QR Code Not Detected

Problem: QR code is not being detected

Solution:

  1. Ensure good lighting conditions
  2. Hold the device steady and at the right distance
  3. Make sure the QR code is not too small or too large in the frame
  4. Check that the QR code is valid and not damaged

Related Packages

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT © Rozo AI