ecsdk-ios-expo
v0.3.1
Published
Expo module for ECSDK-iOS (ELERTS See Say Now SDK)
Maintainers
Readme
ecsdk-ios-expo
Expo module for ECSDK-iOS (ELERTS "See Say Now" SDK) - Complete security and incident reporting solution for React Native apps.
📋 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
- ✅ Background Fetch - Automatic data synchronization
- ✅ TypeScript Support - Full type definitions
- ✅ Config Plugin - Automated native configuration
Platform Support: iOS 15.1+ and tvOS 15.1+
📦 Installation
npm install ecsdk-ios-expo
# or
yarn add ecsdk-ios-expoNote: The ECSDK-iOS library (ELERTSKit) is automatically included via Swift Package Manager. You don't need to add it manually.
⚡ Setup
The config plugin automatically configures all native iOS files including SPM framework integration. No manual native code editing required!
Step 1: Add Plugin to Config
app.config.js or app.config.ts:
export default {
expo: {
name: "My App",
plugins: [
[
"ecsdk-ios-expo",
{
// Required: ELERTSKit API key
apiKey: process.env.EXPO_PUBLIC_ECSDK_API_KEY,
// Optional: Product key (short name for your app without spaces)
// If not provided, can be set via EXPO_PUBLIC_ECSDK_PRODUCT_KEY or Info.plist
productKey: "MyApp",
},
],
],
ios: {
bundleIdentifier: "com.yourcompany.yourapp",
},
},
};The config plugin automatically:
- ✅ Adds ELERTSKitCore and ELERTSKitUI frameworks via SPM
- ✅ Configures framework search paths
- ✅ Sets up framework embedding
- ✅ Injects initialization code into AppDelegate's
willFinishLaunchingWithOptions - ✅ Sets up background fetch manager
- ✅ Injects background fetch handler for store and forward functionality
- ✅ Configures API key and product key
Step 2: Set Up GitHub Authentication
The ELERTSKit-iOS library is hosted on GitHub. Set environment variables for GitHub authentication.
For local development:
export GPR_USER=your-github-username
export GPR_API_KEY=your-personal-access-tokenFor EAS Build, add to eas.json:
{
"build": {
"production": {
"env": {
"GPR_USER": "your-github-username",
"GPR_API_KEY": "your-token"
}
}
}
}Note: You need access to the ELERTS GitHub repository. Contact ELERTS support for access.
Step 3: Build and Run
npx expo prebuild --clean
npx expo run:iosDone! The config plugin handles everything. Skip to API Reference to start using the SDK.
📱 Quick Start Summary
- Install package:
npm install ecsdk-ios-expo - Add config plugin to
app.config.jswith API key and product key - Set GitHub credentials for ELERTSKit library access
- Run:
npx expo prebuild --clean && npx expo run:ios - Register client and join organization
- Start using ECSDK features!
Note: SDK initialization is handled automatically by the config plugin in AppDelegate. No manual initialization code needed!
📖 API Reference
Import
import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";Initialization
Note: SDK initialization is handled automatically by the config plugin. The plugin injects initialization code into AppDelegate's willFinishLaunchingWithOptions, which:
- Initializes ELERTSKit with your API key
- Sets up background fetch manager
- Configures product key
No manual initialization code is required in your app!
Background Fetch: The config plugin also automatically injects the background fetch handler into AppDelegate to enable store and forward functionality when there is poor connectivity. This is handled automatically - no additional code needed!
Client Management
createClient(profile)
Register a new client with the ECSDK system. Must be called before using other features.
Parameters:
{
firstName: string;
lastName: string;
email: string;
phone: string;
otherFields?: Record<string, any>; // Optional additional fields
}Returns: Promise<string> - The client token (save this to your backend!)
Example:
const clientToken = await EcsdkIosExpo.createClient({
firstName: "John",
lastName: "Doe",
email: "[email protected]",
phone: "+1234567890",
});
// IMPORTANT: Save this token!
console.log("Token:", clientToken);updateClientInfo(profile)
Update the client's profile information.
Parameters:
{
firstName: string;
lastName: string;
email: string;
phone: string;
otherFields?: Record<string, any>;
}Returns: Promise<boolean>
Example:
await EcsdkIosExpo.updateClientInfo({
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
EcsdkIosExpo.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
createClient() - 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
EcsdkIosExpo.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 = EcsdkIosExpo.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 EcsdkIosExpo from "ecsdk-ios-expo";
// First-time registration
async function registerNewUser(userData) {
// 1. Register with ECSDK
const clientToken = await EcsdkIosExpo.createClient({
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: clientToken, // 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) {
EcsdkIosExpo.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
EcsdkIosExpo.logout();
// 2. Clear your app's session
await yourAPI.logout();
console.log("User logged out");
}Organization Management
listOrganizations(joined)
Get list of organizations. Returns joined organizations or available organizations based on the parameter.
Parameters:
joined: boolean- Iftrue, returns joined organizations; iffalse, returns available organizations
Returns: Promise<Organization[]>
Example:
// Get available organizations
const availableOrgs = await EcsdkIosExpo.listOrganizations(false);
availableOrgs.forEach((org) => {
console.log(`${org.name} (ID: ${org.organizationId})`);
console.log(` Description: ${org.description}`);
});
// Get joined organizations
const joinedOrgs = await EcsdkIosExpo.listOrganizations(true);
console.log(`User has joined ${joinedOrgs.length} organizations`);joinOrganization(organizationId)
Join an organization. The first organization joined will be set as active.
Parameters:
organizationId: number- The organization ID to join
Returns: Promise<boolean>
Example:
const orgs = await EcsdkIosExpo.listOrganizations(false);
if (orgs.length > 0) {
await EcsdkIosExpo.joinOrganization(orgs[0].organizationId);
console.log(`Joined ${orgs[0].name}`);
}setActiveOrganization(organizationId)
Set which organization is currently active.
Parameters:
organizationId: number- The organization ID
Returns: void
Example:
await EcsdkIosExpo.setActiveOrganization(12345);getActiveOrganization()
Get the currently active organization.
Returns: Organization | { organizationId: 0, name: "", description: "" }
Returns an object with organizationId: 0 if no active organization is set.
Example:
const activeOrg = EcsdkIosExpo.getActiveOrganization();
if (activeOrg.organizationId !== 0) {
console.log("Active:", activeOrg.name);
console.log("Description:", activeOrg.description);
} else {
console.log("No active organization");
}getAvailableOrganizations()
Get list of available organizations (synchronous, returns cached data).
Returns: Organization[]
Example:
const orgs = EcsdkIosExpo.getAvailableOrganizations();
console.log(`Found ${orgs.length} available organizations`);getSelectedOrganizations()
Get selected organizations from user profile (synchronous, returns cached data).
Returns: Organization[]
Example:
const selectedOrgs = EcsdkIosExpo.getSelectedOrganizations();
console.log(`User has selected ${selectedOrgs.length} organizations`);TypeScript Types
interface UserProfile {
firstName: string;
lastName: string;
email: string;
phone: string;
otherFields?: Record<string, any>;
}
interface Organization {
organizationId: number;
name: string;
description: string;
}💡 Complete Example
import React, { useEffect, useState } from "react";
import { View, Button, Alert, Text } from "react-native";
import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";
export default function App() {
const [isRegistered, setIsRegistered] = useState(false);
const [activeOrg, setActiveOrg] = useState<Organization | null>(null);
const [initialized, setInitialized] = useState(false);
useEffect(() => {
initializeECSDK();
}, []);
async function initializeECSDK() {
try {
// SDK is automatically initialized by the config plugin in AppDelegate
// Try to access the SDK to verify it's ready
const token = EcsdkIosExpo.getClientToken();
setInitialized(true); // SDK is ready (initialized in AppDelegate)
// Check if user is already registered
if (token) {
setIsRegistered(true);
// Refresh organization data
await refreshOrganizationData();
}
} catch (error: any) {
// Even if there's an error, SDK should be initialized in AppDelegate
setInitialized(true);
Alert.alert("Initialization Error", error.message);
console.error("Init error:", error);
}
}
async function refreshOrganizationData() {
const activeOrg = EcsdkIosExpo.getActiveOrganization();
if (activeOrg.organizationId !== 0) {
setActiveOrg(activeOrg);
}
}
async function handleRegister() {
if (!initialized) {
Alert.alert("Error", "Please wait for SDK initialization");
return;
}
try {
// Register client
const clientToken = await EcsdkIosExpo.createClient({
firstName: "John",
lastName: "Doe",
email: "[email protected]",
phone: "+1234567890",
});
// Save the token to your backend!
console.log("Client Token:", clientToken);
setIsRegistered(true);
// Update profile
await EcsdkIosExpo.updateClientInfo({
firstName: "John",
lastName: "Doe",
email: "[email protected]",
phone: "+1234567890",
});
// Get and join organization
const organizations = await EcsdkIosExpo.listOrganizations(false);
if (organizations.length > 0) {
// Join first organization
await EcsdkIosExpo.joinOrganization(organizations[0].organizationId);
EcsdkIosExpo.setActiveOrganization(organizations[0].organizationId);
// Get active organization
const org = EcsdkIosExpo.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("Registration Error", error.message);
console.error("Registration error:", error);
}
}
return (
<View style={{ flex: 1, justifyContent: "center", padding: 20 }}>
<Text style={{ marginBottom: 20, textAlign: "center" }}>
ECSDK iOS Example
</Text>
{!isRegistered && (
<Button
title="Register Client"
onPress={handleRegister}
disabled={!initialized}
/>
)}
{isRegistered && (
<>
<Text style={{ marginBottom: 10 }}>
Status: Registered
</Text>
{activeOrg && activeOrg.organizationId !== 0 && (
<Text style={{ marginBottom: 10 }}>
Active Org: {activeOrg.name}
</Text>
)}
</>
)}
</View>
);
}🐛 Troubleshooting
Build fails with "Could not resolve ELERTSKit"
Solution: Check GitHub authentication. The ELERTSKit-iOS library requires GitHub authentication to access the private repository.
Verify environment variables:
echo $GPR_USER echo $GPR_API_KEYFor EAS Build, add to
eas.json:{ "build": { "production": { "env": { "GPR_USER": "your-github-username", "GPR_API_KEY": "your-token" } } } }Contact ELERTS support if you don't have access to the repository
"Unable to resolve host" or Network errors
Solution:
Clean and rebuild:
cd ios pod deintegrate pod install cd .. npx expo run:iosCheck internet connection: SPM requires internet access to download packages
Test on physical device: Network issues are sometimes simulator-specific
"No active organization" error
Solution: Join an organization first
const orgs = await EcsdkIosExpo.listOrganizations(false);
if (orgs.length > 0) {
await EcsdkIosExpo.joinOrganization(orgs[0].organizationId);
EcsdkIosExpo.setActiveOrganization(orgs[0].organizationId);
}App crashes on startup
Solution: Verify SDK is configured correctly in plugin options
// In app.config.ts, make sure you have:
plugins: [
[
"ecsdk-ios-expo",
{
apiKey: process.env.EXPO_PUBLIC_ECSDK_API_KEY, // Required
productKey: "YourProductKey", // Optional
},
],
],The SDK is automatically initialized in AppDelegate by the config plugin. No manual initialization code needed!
Config plugin not applying changes
Solution:
npx expo prebuild --clean
cd ios
pod install
cd ..
npx expo run:iosSPM framework not found errors
Solution: The config plugin should handle this automatically, but if you see framework errors:
Clean build folder:
cd ios xcodebuild clean -workspace YourApp.xcworkspace -scheme YourAppRe-run prebuild:
npx expo prebuild --cleanVerify Podfile has post_install block with SPM framework code (added by config plugin)
TypeScript errors
Solution: Make sure you're importing types correctly
import EcsdkIosExpo, { Organization, UserProfile } from "ecsdk-ios-expo";"No client token available" error
Solution: Make sure you've registered a client or logged in with a saved token
// Register new client
const token = await EcsdkIosExpo.createClient({...});
// Or login with saved token
EcsdkIosExpo.login(savedToken);📄 License
MIT
🤝 Support
- SDK Issues: Contact ELERTS support
- Module Issues: GitHub Issues
- API Key: Contact ELERTS to get your API key
🙏 Credits
- ECSDK-iOS SDK (ELERTSKit) by ELERTS
- Built with Expo Modules
- Created for the React Native community
Version: 0.1.0
Made for the React Native community 🚀
