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 🙏

© 2026 – Pkg Stats / Ryan Hefner

native-android-sms

v0.0.2

Published

Manage Android phone SMS

Downloads

60

Readme

Native Android SMS

npm version npm downloads License: MIT Node.js Version

A high-performance React Native module to manage SMS functionality on Android devices. Supports background SMS dispatch, personalized and broadcast bulk SMS, multi-SIM / Dual-SIM management, SIM health checks, delivery status event tracking, GSM-7/Unicode segment analysis, text sanitization, and permission controls.

Table of Contents


Features

  • 📱 Direct Background SMS: Send SMS silently in the background without UI interruption.
  • 🚀 Personalized & Broadcast Bulk SMS: Send identical messages to many recipients or distinct personalized messages per recipient with native delay pacing.
  • 📊 Progress & Result Reporting: Built-in helper sendBulkSmsWithProgressAsync for live UI progress bars and individual failure logs.
  • 📶 Multi-SIM / Dual-SIM Support: Query SIM slots, carrier names, country ISOs, and specify active SIM cards.
  • 🛡️ Active SIM Detection & Fallback: Automatically filter out ghost/inactive SIM slots ("Emergency calls only", "No service") with optional fallback to the default SIM.
  • 🔤 GSM-7 Text Sanitization: Convert smart quotes, em-dashes, and special whitespace to prevent accidental multi-segment UCS-2/Unicode billing expansions.
  • 📏 SMS Segment Counter: Accurately compute character counts, segment thresholds, and Unicode detection.
  • 📡 Delivery & Sent Event Listeners: Track cellular carrier ACK (sent) and handset delivery reports (delivered).
  • 💬 Composer UI Fallback: Launch the system SMS composer (smsto:) across Android and iOS.

Installation

npm install native-android-sms

Since this library uses native Android code, run expo prebuild to build your project using local builds or EAS Build.


Quick Start

import React, { useEffect, useState } from 'react';
import { View, Text, Button, Alert } from 'react-native';
import * as Sms from 'native-android-sms';

export default function SmsApp() {
  const [sims, setSims] = useState<Sms.SimInfo[]>([]);

  useEffect(() => {
    // Listen for SMS status updates from the cell radio
    const sentSub = Sms.addSmsSentListener((event) => {
      console.log('SMS Sent Status:', event.uuid, event.status, event.error);
    });

    const deliveredSub = Sms.addSmsDeliveredListener((event) => {
      console.log('SMS Delivered Status:', event.uuid, event.status);
    });

    return () => {
      sentSub.remove();
      deliveredSub.remove();
    };
  }, []);

  const handleSend = async () => {
    // 1. Request SMS permission (granularly without requiring READ_PHONE_STATE)
    const perm = await Sms.requestPermissionsAsync({ sendSms: true });
    if (!perm.sendSms) {
      Alert.alert('Permission Denied', 'SEND_SMS permission is required.');
      return;
    }

    // 2. Fetch active SIM cards (filters out empty/inactive slots by default)
    const activeSims = await Sms.getAvailableSimsAsync();
    setSims(activeSims);

    const subscriptionId = activeSims[0]?.subscriptionId;

    // 3. Send SMS with optional SIM fallback and text sanitization
    try {
      const uuid = await Sms.sendSmsAsync('+1234567890', '“Hello World”—Welcome!', {
        subscriptionId,
        fallbackToDefaultSim: true,
        sanitize: true, // Replaces curly quotes & dashes with standard GSM-7
      });
      Alert.alert('Dispatched', `Message queued with UUID: ${uuid}`);
    } catch (error: any) {
      Alert.alert('Error', error.message);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Active SIMs: {sims.length}</Text>
      <Button title="Send SMS" onPress={handleSend} />
    </View>
  );
}

API Reference

SMS Dispatch

sendSmsAsync(phoneNumber, message, optionsOrSubscriptionId?)

Sends an SMS in the background. Returns a unique UUID tracking the message.

  • phoneNumber: Recipient phone number in standard or E.164 format.
  • message: Text content.
  • optionsOrSubscriptionId: A numeric subscriptionId or an options object:
    • subscriptionId?: number | null: Specific SIM slot to send from.
    • fallbackToDefaultSim?: boolean: If sending via the specified SIM fails, automatically retry using the Android default SMS SIM.
    • sanitize?: boolean: Automatically normalize curly quotes, unicode dashes, and non-breaking spaces into standard GSM-7 characters before dispatch.

sendSmsUIAsync(phoneNumber, message)

Launches the system SMS composer pre-filled with the provided recipient and message. Works on Android and iOS.


Bulk SMS Dispatch

sendBulkSmsAsync(recipients, options?)

Dispatches personalized messages to multiple recipients in a high-performance native Android background coroutine (Dispatchers.IO).

  • recipients: Array of BulkSmsRecipient:
    interface BulkSmsRecipient {
      to: string;
      message: string;
      recipientName?: string;
      id?: string;
    }
  • options: Optional configuration:
    • delayMs?: number: Milliseconds delay between consecutive sends (default: 1000).
    • subscriptionId?: number | null: Target SIM card.
    • fallbackToDefaultSim?: boolean: Retries on the default SIM if specific SIM fails.
    • sanitize?: boolean: Sanitizes all messages into GSM-7 format.

sendBulkSmsAsync(phoneNumbers, message, options?)

Broadcasts an identical message to an array of phone numbers natively.

sendBulkSmsWithProgressAsync(recipients, options?)

Convenience method for user interfaces needing real-time dispatch progress and detailed success/failure breakdowns:

const result = await Sms.sendBulkSmsWithProgressAsync(recipients, {
  delayMs: 2000,
  fallbackToDefaultSim: true,
  sanitize: true,
  onProgress: ({ current, total, label, currentRecipient }) => {
    console.log(`[${current}/${total}] ${label}`);
  },
});

console.log(`Sent: ${result.successCount}, Failed: ${result.failedCount}`);

SIM Card Management

getAvailableSimsAsync(options?)

Returns an array of available SIM cards.

  • options.includeInactive?: boolean: Defaults to false. When false, automatically filters out inactive slots ("No service", "Emergency calls only", "No SIM", "Disabled").

Returns SimInfo[]:

interface SimInfo {
  subscriptionId: number;
  displayName: string;
  carrierName: string;
  slotIndex: number;
  number?: string;
  countryIso?: string; // e.g. "ke", "us"
  isActive?: boolean;
}

canSendSmsAsync(): Promise<boolean>

Checks if the current device has telephony hardware capable of sending SMS.


Permissions

requestPermissionsAsync(options?): Promise<PermissionResponse>

Requests permissions granularly:

// Request only SEND_SMS without READ_PHONE_STATE
const res = await Sms.requestPermissionsAsync({ sendSms: true, readPhoneState: false });
console.log(res.sendSms); // boolean

getPermissionsAsync(options?): Promise<PermissionResponse>

Checks the current permission status.


Utilities

sanitizeSmsText(text: string): string

Normalizes smart quotes (‘’“”), en/em dashes (–—), ellipsis (), and non-breaking spaces into GSM-7 equivalents, preventing unintended 70-character UCS-2 multi-part expansions.

getSmsSegmentInfo(text: string): SmsSegmentInfo

Analyzes string content to determine segment count, remaining characters in the current segment, and encoding mode:

interface SmsSegmentInfo {
  chars: number;
  segments: number;
  isUnicode: boolean;
  limit: number; // 160 for GSM-7, 70 for Unicode
  remaining: number; // Characters left in current segment
}

isSimActive(sim: { carrierName?: string; displayName?: string }): boolean

Helper to test if a carrier or display name indicates an active cellular carrier.


Events

addSmsSentListener(listener: (event: SmsStatusEvent) => void): EventSubscription

Fires when the device's radio hands over the SMS to the mobile carrier tower. Includes error reason if failed (e.g. GENERIC_FAILURE, NO_SERVICE, RADIO_OFF).

addSmsDeliveredListener(listener: (event: SmsStatusEvent) => void): EventSubscription

Fires when the recipient's phone sends back a delivery receipt (subject to carrier support).


Types

interface SmsStatusEvent {
  uuid: string;
  status: 'sent' | 'delivered' | 'failed';
  error?: string;
}

interface BulkSmsResult {
  total: number;
  successCount: number;
  failedCount: number;
  uuids: string[];
  successful: Array<{ to: string; message: string; uuid?: string }>;
  failed: Array<{ to: string; message: string; error: string }>;
}

Android Permissions & Policies

The module includes standard permissions in its Android Manifest:

  • android.permission.SEND_SMS
  • android.permission.READ_PHONE_STATE

Note: Background SMS dispatch is restricted by Google Play Store policies. Ensure your app falls within Google's permitted use-cases (such as Enterprise / CRM / Default SMS Handler / Financial transaction alerts) before publishing to the Play Store.