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

ecsdk-android-expo

v2.0.1

Published

Expo module for ECSDK-Android (ELERTS See Say Now SDK)

Readme

ecsdk-android-expo

Expo module for ECSDK-Android (ELERTS "See Say Now" SDK) - Complete security and incident reporting solution for React Native apps.

npm version License: MIT

📋 Table of Contents


✨ Features

  • Client Registration - Register users with the ECSDK system
  • User Login/Logout - Manage user sessions with saved tokens
  • Profile Management - Update user information
  • Organization Management - Join and manage organizations
  • Report Submission - Submit incident reports with photos and location
  • Message Center - View alerts and notifications
  • Push Notifications - Firebase Cloud Messaging for real-time alerts
  • Emergency Calling - Call emergency services with dispatch notification
  • Profile Screen - Built-in user profile UI
  • Notification Customization - Customize notification icons and colors
  • TypeScript Support - Full type definitions
  • Config Plugin - Automated native configuration

Platform Support: Android only (API 23+)


📦 Installation

npm install ecsdk-android-expo @react-native-firebase/app @react-native-firebase/messaging
# or
yarn add ecsdk-android-expo @react-native-firebase/app @react-native-firebase/messaging

Required Peer Dependencies:

  • @react-native-firebase/app - Firebase core (required for Firebase initialization)
  • @react-native-firebase/messaging - Firebase Cloud Messaging (required for push notifications)

Why are Firebase dependencies required?

While this module includes native Firebase messaging support, the React Native Firebase packages are required because:

  1. They initialize Firebase in the React Native context
  2. They process the google-services.json configuration during build
  3. They enable FCM token generation and management
  4. They handle foreground notification reception

The module's native code depends on Firebase being properly initialized by these packages.

Note: The ECSDK-Android library is already included as a dependency. You don't need to add it to your build.gradle.


⚡ Setup

The config plugin automatically configures all native Android files including ECSDK initialization. No manual native code editing required!

Step 1: Add Plugin to Config

app.config.js (with environment variables):

export default {
  expo: {
    name: "My App",
    plugins: [
      [
        "ecsdk-android-expo",
        {
          ecsdkApiKey: process.env.ECSDK_API_KEY,
          googleMapsApiKey: process.env.GOOGLE_MAPS_API_KEY,
          googleServicesFile: "./google-services.json",
          productName: "PROVIDED BY ELERTS",
          appName: "My App Name",
          shortDisplayName: "MyApp",
        },
      ],
    ],
  },
};

Config Options

| Option | Required | Default | Description | | -------------------- | -------- | ---------------------- | ----------------------------------------------- | | ecsdkApiKey | Yes | - | Your ECSDK API key from ELERTS | | googleMapsApiKey | Yes | - | Google Maps API key (required for map features) | | googleServicesFile | No | - | Path to google-services.json (for FCM) | | productName | No | "PROVIDED BY ELERTS" | Product name shown in ECSDK UI | | appName | No | - | Your app name (optional) | | shortDisplayName | No | - | Short display name for your app |

Step 2: Configure Firebase

Automatic Setup (Recommended)

Place your google-services.json in your project root and configure the plugin:

{
  "plugins": [
    [
      "ecsdk-android-expo",
      {
        ...
        "googleServicesFile": "./google-services.json"
        ...
      }
    ]
  ]
}

Getting Your FCM Server Key for ELERTS

To enable push notifications, you need to provide your FCM Server Key to ELERTS:

Step 1: Get Your FCM Server Key

  1. Go to Firebase Console
  2. Select your project
  3. Click the gear icon (⚙️) → Project settings
  4. Go to the Cloud Messaging tab
  5. Scroll to Cloud Messaging API (Legacy)
  6. Copy the Server key value

Step 2: Provide to ELERTS

Contact ELERTS support with:

  • Your ECSDK API Key
  • Your FCM Server Key
  • Your app's package name (e.g., com.yourcompany.yourapp)

Important Notes:

  • Keep your FCM Server Key secure and never commit it to version control
  • The FCM Server Key allows ELERTS to send push notifications to your app
  • Without providing this key to ELERTS, push notifications will not work

Step 3: Set Up GitHub Authentication

Set environment variables for GitHub authentication.

For local development:

export GPR_USER=your-github-username
export GPR_API_KEY=your-personal-access-token

For EAS Build, add to eas.json:

{
  "build": {
    "production": {
      "env": {
        "GPR_USER": "your-github-username",
        "GPR_API_KEY": "your-token"
      }
    }
  }
}

Step 4: Build and Run

npx expo prebuild --clean
npx expo run:android

Done! The config plugin handles everything:

  • ✅ AndroidManifest.xml configuration (including FCM service)
  • ✅ String resources setup
  • ✅ ECSDK initialization in MainApplication
  • ✅ Firebase Messaging Service registration
  • ✅ Auto-copy google-services.json (if path provided)

Skip to API Reference to start using the SDK.


📱 Quick Start Summary

  1. Install packages: npm install ecsdk-android-expo @react-native-firebase/app @react-native-firebase/messaging
  2. Add config plugin to app.config.js with your API keys
  3. Place google-services.json in project (plugin auto-copies)
  4. Set GitHub credentials for ECSDK library access
  5. Run: npx expo prebuild --clean && npx expo run:android
  6. Register client and join organization
  7. Provide FCM Server Key to ELERTS support
  8. Start receiving push notifications!

📖 API Reference

Import

import { ECSDK, ECOrganizationData, ECClientData } from "ecsdk-android-expo";

Client Management

registerClient(userData)

Register a new client with the ECSDK system. Must be called before using other features.

Parameters:

{
  deviceId?: string;     // Unique device ID (auto-generated if not provided)
  firstName?: string;    // User's first name
  lastName?: string;     // User's last name
  email?: string;        // User's email
  phone?: string;        // User's phone number
}

Returns: Promise<ECClientData>

{
  token: string; // Save this token to your backend!
}

Example:

const clientData = await ECSDK.registerClient({
  deviceId: "unique-device-id",
  firstName: "John",
  lastName: "Doe",
  email: "[email protected]",
  phone: "+1234567890",
});

// IMPORTANT: Save this token!
console.log("Token:", clientData.token);

updateClient(userData)

Update the client's profile information.

Parameters:

{
  firstName?: string;
  lastName?: string;
  email?: string;
  phone?: string;
}

Returns: Promise<void>

Example:

await ECSDK.updateClient({
  firstName: "Jane",
  lastName: "Smith",
  email: "[email protected]",
  phone: "+1987654321",
});

User Login/Logout Management

Important for apps with user login systems: If your app has user authentication, you must save the ELERTS client token on your server with each user's data. When a user logs back in, retrieve their token and restore their ELERTS session.

login(clientToken)

Login a user with their saved ELERTS client token. Call this when a user logs into your app to restore their ELERTS session.

Parameters:

  • clientToken: string - The ELERTS client token retrieved from your server

Returns: void

Example:

// Typical login flow:
async function handleUserLogin(username, password) {
  // 1. Authenticate user with your backend
  const user = await yourAuthAPI.login(username, password);
  
  // 2. Retrieve the ELERTS token saved for this user
  const elertsToken = user.elertsClientToken;
  
  // 3. Login to ELERTS
  ECSDK.login(elertsToken);
  
  // User can now submit reports and receive messages
}

Important Notes:

  • The ELERTS token should be saved to your server when the user first registers with registerClient()
  • Upon login, retrieve this token from your server and pass it to login()
  • If you want to allow non-logged-in users to send reports, use an ELERTS webform instead

logout()

Logout the current user and clear their ELERTS session. Call this when a user logs out of your app.

Returns: void

Example:

async function handleUserLogout() {
  // Clear ELERTS session
  ECSDK.logout();
  
  // Then clear your app's session
  await yourAuthAPI.logout();
}

Note: After logout, the user will not be able to submit reports or receive ELERTS messages until they log back in.


getClientToken()

Get the current ELERTS client token. Returns null if no user is logged in.

Returns: string | null

Example:

const token = ECSDK.getClientToken();

if (token) {
  console.log("User is logged in to ELERTS");
  // Optionally save token to your server if not already saved
  await saveTokenToServer(currentUserId, token);
} else {
  console.log("No user logged in to ELERTS");
}

Use Cases:

  • Check if a user is currently logged in
  • Retrieve the token to save to your server
  • Verify login/logout operations

Complete Login Flow Example

import { ECSDK } from "ecsdk-android-expo";

// First-time registration
async function registerNewUser(userData) {
  // 1. Register with ECSDK
  const clientData = await ECSDK.registerClient({
    deviceId: `device-${Date.now()}`,
    firstName: userData.firstName,
    lastName: userData.lastName,
    email: userData.email,
    phone: userData.phone,
  });
  
  // 2. Save the ELERTS token to your server
  await yourAPI.saveUserData({
    userId: userData.userId,
    elertsClientToken: clientData.token, // IMPORTANT!
    ...userData
  });
  
  // User is now registered and logged in
}

// Returning user login
async function loginExistingUser(username, password) {
  // 1. Authenticate with your backend
  const user = await yourAPI.login(username, password);
  
  // 2. Retrieve the saved ELERTS token
  const elertsToken = user.elertsClientToken;
  
  // 3. Login to ELERTS
  if (elertsToken) {
    ECSDK.login(elertsToken);
    console.log("Logged in to ELERTS");
  } else {
    console.warn("No ELERTS token found for user");
  }
}

// User logout
async function logoutUser() {
  // 1. Logout from ELERTS
  ECSDK.logout();
  
  // 2. Clear your app's session
  await yourAPI.logout();
  
  console.log("User logged out");
}

Organization Management

getOrganizationList()

Get all available organizations that the client can join.

Returns: Promise<ECOrganizationData[]>

Example:

const organizations = await ECSDK.getOrganizationList();

organizations.forEach((org) => {
  console.log(`${org.name} (ID: ${org.id})`);
  console.log(`  Phone: ${org.phone}`);
});

joinOrganizations(organizationIds)

Join one or more organizations. The first organization will be set as active.

Parameters:

  • organizationIds: string[] - Array of organization IDs

Returns: Promise<{ success: boolean }>

Example:

const orgs = await ECSDK.getOrganizationList();

if (orgs.length > 0) {
  await ECSDK.joinOrganizations([orgs[0].id.toString()]);
  console.log(`Joined ${orgs[0].name}`);
}

setActiveOrganization(organizationId)

Set which organization is currently active.

Parameters:

  • organizationId: string - The organization ID

Returns: Promise<{ success: boolean }>

Example:

await ECSDK.setActiveOrganization("12345");

getActiveOrganization()

Get the currently active organization.

Returns: Promise<ECOrganizationData | null>

Example:

const activeOrg = await ECSDK.getActiveOrganization();

if (activeOrg) {
  console.log("Active:", activeOrg.name);
  console.log("Phone:", activeOrg.phone);
} else {
  console.log("No active organization");
}


Push Notifications (FCM)

Permission Handling

Important: On Android 13+ (API 33+), you must request the POST_NOTIFICATIONS permission from the user to receive push notifications.

The config plugin automatically adds this permission to your AndroidManifest.xml, but you need to request it at runtime:

import { Platform, PermissionsAndroid } from "react-native";

async function requestNotificationPermission() {
  if (Platform.OS === "android" && Platform.Version >= 33) {
    const granted = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
    );
    return granted === PermissionsAndroid.RESULTS.GRANTED;
  }
  return true; // Permission not required on older versions
}

// Request permission before getting token or registering
await requestNotificationPermission();

Notes:

  • FCM token can be retrieved without permission, but notifications won't be received
  • Permission is not required on Android 12 and below
  • The example app demonstrates complete permission handling

getFCMToken()

Get the current Firebase Cloud Messaging token.

Returns: Promise<string>

Example:

const fcmToken = await ECSDK.getFCMToken();
console.log("FCM Token:", fcmToken);

updateFCMToken(token?)

Manually update the FCM token with the ELERTS server.

Note: This is done automatically by the FirebaseMessagingService, but you can call it manually if needed.

Parameters:

  • token?: string - FCM token (optional, will get current token if not provided)

Returns: Promise<{ success: boolean }>

Example:

// Automatic - just call without parameters
await ECSDK.updateFCMToken();

// Or with a specific token
const token = await ECSDK.getFCMToken();
await ECSDK.updateFCMToken(token);

getStoredFCMToken()

Get the FCM token stored in local preferences.

Returns: string | null

Example:

const storedToken = ECSDK.getStoredFCMToken();
if (storedToken) {
  console.log("Stored token:", storedToken);
}

Notification Customization

setSmallNotificationIcon(resourceName)

Set the small notification icon (appears in status bar).

Parameters:

  • resourceName: string - Name of drawable resource (e.g., "notification_icon")

Example:

// Icon must exist in android/app/src/main/res/drawable/
ECSDK.setSmallNotificationIcon("notification_icon");

setSmallNotificationIconColor(color)

Set the tint color for the small notification icon.

Parameters:

  • color: string - Hex color (#RRGGBB or #AARRGGBB)

Example:

ECSDK.setSmallNotificationIconColor("#2196F3");

// With alpha transparency
ECSDK.setSmallNotificationIconColor("#802196F3");

setLargeNotificationIcon(base64Image)

Set the large notification icon from a base64-encoded image.

Parameters:

  • base64Image: string - Base64 image string (without data:image prefix)

Example:

import * as FileSystem from "expo-file-system";

// Convert image to base64
const base64 = await FileSystem.readAsStringAsync(imageUri, {
  encoding: FileSystem.EncodingType.Base64,
});

ECSDK.setLargeNotificationIcon(base64);

configureNotificationIcons(config)

Configure all notification icon properties at once.

Parameters:

{
  smallIconResourceName?: string;
  smallIconColor?: string;
  largeIconBase64?: string;
}

Example:

ECSDK.configureNotificationIcons({
  smallIconResourceName: "notification_icon",
  smallIconColor: "#2196F3",
  largeIconBase64: base64Icon,
});

UI Components

showReportActivity()

Display the ECSDK incident report screen.

⚠️ Requires an active organization.

Example:

try {
  ECSDK.showReportActivity();
} catch (error) {
  console.error("No active organization");
}

showMessageList()

Display the message list screen with alerts and notifications.

Example:

ECSDK.showMessageList();

showCallPrompt()

Display emergency call dialog. Sends notification to dispatch console.

Example:

ECSDK.showCallPrompt();

showProfileScreen()

Display the built-in user profile screen.

Example:

ECSDK.showProfileScreen();

TypeScript Types

type ECUserData = {
  deviceId?: string;
  firstName?: string;
  lastName?: string;
  email?: string;
  phone?: string;
};

type ECClientData = {
  token: string;
};

type ECOrganizationData = {
  id: number;
  name: string;
  phone: string;
  phoneTitle: string;
};

type FCMTokenResponse = {
  success: boolean;
};

type NotificationIconConfig = {
  smallIconResourceName?: string;
  smallIconColor?: string;
  largeIconBase64?: string;
};

💡 Complete Example

import React, { useEffect, useState } from "react";
import { View, Button, Alert } from "react-native";
import { ECSDK, ECOrganizationData } from "ecsdk-android-expo";

export default function App() {
  const [isRegistered, setIsRegistered] = useState(false);
  const [activeOrg, setActiveOrg] = useState<ECOrganizationData | null>(null);

  useEffect(() => {
    initializeECSDK();
  }, []);

  async function initializeECSDK() {
    try {
      // 1. Request notification permission (Android 13+)
      if (Platform.OS === "android" && Platform.Version >= 33) {
        const granted = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
        );
        if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
          console.warn("Notification permission denied");
        }
      }

      // 2. Register client
      const clientData = await ECSDK.registerClient({
        deviceId: `device-${Date.now()}`,
      });

      // Save the token to your backend!
      console.log("Client Token:", clientData.token);
      setIsRegistered(true);

      // 3. Update profile
      await ECSDK.updateClient({
        firstName: "John",
        lastName: "Doe",
        email: "[email protected]",
        phone: "+1234567890",
      });

      // 4. Setup push notifications
      const fcmToken = await ECSDK.getFCMToken();
      console.log("FCM Token:", fcmToken);
      await ECSDK.updateFCMToken();

      // 5. Customize notifications (optional)
      ECSDK.configureNotificationIcons({
        smallIconColor: "#2196F3",
      });

      // 6. Get and join organization
      const organizations = await ECSDK.getOrganizationList();

      if (organizations.length > 0) {
        // Join first organization
        await ECSDK.joinOrganizations([organizations[0].id.toString()]);

        // Get active organization
        const org = await ECSDK.getActiveOrganization();
        setActiveOrg(org);

        Alert.alert("Success", `Ready to use ECSDK with ${org?.name}`);
      } else {
        Alert.alert("Error", "No organizations available. Check your API key.");
      }
    } catch (error: any) {
      Alert.alert("Initialization Error", error.message);
      console.error("Init error:", error);
    }
  }

  return (
    <View style={{ flex: 1, justifyContent: "center", padding: 20 }}>
      <Button
        title="Submit Report"
        onPress={() => ECSDK.showReportActivity()}
        disabled={!activeOrg}
      />

      <Button
        title="View Messages"
        onPress={() => ECSDK.showMessageList()}
        disabled={!isRegistered}
      />

      <Button
        title="Call Police"
        onPress={() => ECSDK.showCallPrompt()}
        disabled={!activeOrg}
      />

      <Button
        title="View Profile"
        onPress={() => ECSDK.showProfileScreen()}
        disabled={!isRegistered}
      />
    </View>
  );
}

🐛 Troubleshooting

"Peer dependency not installed" warnings

Solution:

Make sure you've installed the required Firebase peer dependencies:

npm install @react-native-firebase/app @react-native-firebase/messaging

These are required for the module to function properly. See the Installation section for details.

Push notifications not working

Solution:

  1. Verify Firebase setup:

    • google-services.json is in android/app/
    • Firebase dependencies are installed (@react-native-firebase/app and @react-native-firebase/messaging)
    • App package name matches Firebase project
  2. Check FCM Server Key:

    • You provided the FCM Server Key to ELERTS support
    • The key is from the correct Firebase project
    • Use the "Server key" from Cloud Messaging API (Legacy)
  3. Test FCM directly:

    • Use Firebase Console → Cloud Messaging → Send test message
    • If this works, the issue is with ELERTS configuration
    • If this fails, check your Firebase setup
  4. Check permissions (Android 13+):

    <!-- AndroidManifest.xml -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
  5. Verify token registration:

    const token = await ECSDK.getFCMToken();
    console.log("Token:", token); // Should not be null
    
    const stored = ECSDK.getStoredFCMToken();
    console.log("Stored:", stored); // Should match

Build fails with "Could not resolve com.elerts.libraries:elertsui"

Solution: Check GitHub authentication. See the setup documentation for details on configuring GitHub credentials.

"Unable to resolve host" or Network errors

Solution:

  1. Clean and rebuild:

    cd android
    ./gradlew clean
    cd ..
    npx expo run:android
  2. Restart emulator: Cold boot your Android emulator

  3. Test on physical device: Network issues are often emulator-specific

"No active organization" error

Solution: Join an organization first

const orgs = await ECSDK.getOrganizationList();
await ECSDK.joinOrganizations([orgs[0].id.toString()]);

App crashes on startup

Solution: Verify ECSDK is initialized in your MainApplication class

class MainApplication : Application() {
    private lateinit var ecuisdk: ECUISDK

    override fun onCreate() {
        super.onCreate()
        ecuisdk = ECUISDK(this)  // Make sure this is here
    }
}

Config plugin not applying changes

Solution:

npx expo prebuild --clean
npx expo run:android

TypeScript errors

Solution: Make sure you're importing types correctly

import { ECSDK, ECOrganizationData, ECClientData } from "ecsdk-android-expo";

📄 License

MIT

🤝 Support

  • SDK Issues: Contact ELERTS support
  • Module Issues: GitHub Issues
  • API Key: Contact ELERTS to get your API key

🙏 Credits

  • ECSDK-Android SDK by ELERTS
  • Built with Expo Modules
  • Created for the React Native community

Version: 1.2.0
Made for the React Native community 🚀