UNPKG

expo-pngme-sdk

Version:

Expo SDK for Pngme financial insights - Android only, optimized for managed workflow

481 lines (391 loc) 11.2 kB
# Expo Pngme SDK A native Expo module for integrating Pngme's financial insights SDK into your Expo managed workflow apps. This SDK enables credit scoring and financial analysis through SMS data collection on Android devices. ## 🎯 Designed for Expo Managed Workflow This SDK is specifically optimized for **Expo Managed Workflow** projects. No ejecting required! ## 📱 Platform Support | Platform | Support | |----------|---------| | Android | ✅ Full Support | | iOS | ❌ Not Supported | | Web | ⚠️ Development Stub | ## 🚀 Installation ### Step 1: Install the Package ```bash npm install expo-pngme-sdk # or yarn add expo-pngme-sdk # or expo install expo-pngme-sdk ``` ### Step 2: Add to App Config In your `app.json` or `app.config.js`, add the plugin: ```json { "expo": { "plugins": [ "expo-pngme-sdk" ] } } ``` Or with custom configuration: ```json { "expo": { "plugins": [ [ "expo-pngme-sdk", { "pngmeSdkVersion": "7.0.6", "pngmeMavenUrl": "https://jitpack.io" } ] ] } } ``` ### Step 3: Create a Development Build **⚠️ Important**: This SDK does NOT work with Expo Go due to native module requirements. ```bash # Using EAS Build (recommended) eas build --profile development --platform android # Or using local build expo run:android ## 💻 Usage ### Basic Implementation ```typescript import PngmeSDK from 'expo-pngme-sdk'; const initializePngme = async () => { try { await PngmeSDK.go({ clientKey: 'YOUR_PNGME_CLIENT_KEY', // Required externalId: 'user_123', // Required: Your user ID companyName: 'Your Company', // Required firstName: 'John', // Optional lastName: 'Doe', // Optional email: 'john@example.com', // Optional phoneNumber: '254712345678', // Optional }); console.log('Pngme SDK initialized successfully'); } catch (error) { console.error('Failed to initialize:', error); } }; ``` ### Custom Dialog Styling ```typescript await PngmeSDK.go({ clientKey: 'YOUR_CLIENT_KEY', externalId: 'user_123', companyName: 'Your Company', dialogStyle: { // Colors primaryColor: '#007AFF', backgroundColor: '#FFFFFF', buttonBackgroundColor: '#007AFF', buttonTextColor: '#FFFFFF', // Text customTitle: 'Enable Financial Insights', customButtonText: 'Get Started', // Sizing titleTextSize: 24, bodyTextSize: 16, buttonCornerRadius: 8, // URLs privacyPolicyUrl: 'https://yourcompany.com/privacy', eulaUrl: 'https://yourcompany.com/terms', } }); ``` ### Event Handling ```typescript import { useEffect } from 'react'; import PngmeSDK from 'expo-pngme-sdk'; export default function App() { useEffect(() => { const subscriptions = [ PngmeSDK.addListener('onPermissionGranted', (event) => { console.log('Permission granted:', event.status); }), PngmeSDK.addListener('onSignInComplete', (event) => { console.log('User ID:', event.userId); }), PngmeSDK.addListener('onError', (event) => { console.error('Error:', event.error); }), ]; return () => { subscriptions.forEach(sub => sub.remove()); }; }, []); // ... rest of your app } ``` ### Check Permission Status ```typescript const checkStatus = async () => { const isGranted = await PngmeSDK.isPermissionGranted(); const status = await PngmeSDK.getPermissionStatus(); console.log('SMS Permission:', status.smsPermission); console.log('Terms Accepted:', status.termsAccepted); }; ``` ## 📖 API Reference ### Methods | Method | Description | Returns | |--------|-------------|---------| | `go(config)` | Initialize SDK and show dialog | `Promise<void>` | | `isPermissionGranted()` | Check if permissions granted | `Promise<boolean>` | | `getUserUuid()` | Get Pngme user ID | `Promise<string \| null>` | | `setDefaultStyle(style)` | Set default dialog style | `Promise<void>` | | `clearDefaultStyle()` | Clear default style | `Promise<void>` | | `getPermissionStatus()` | Get detailed permission status | `Promise<PngmePermissionStatus>` | ### Events | Event | Payload | Description | |-------|---------|-------------| | `onPermissionGranted` | `{ status }` | Permissions granted | | `onPermissionDenied` | `{ status }` | Permissions denied | | `onDialogDismissed` | `{ completed }` | Dialog closed | | `onSignInComplete` | `{ userId }` | User authenticated | | `onSmsUploadStarted` | `{ timestamp }` | SMS sync started | | `onSmsUploadComplete` | `{ success, count? }` | SMS sync finished | | `onError` | `{ error, code }` | Error occurred | ### Types ```typescript interface PngmeConfig { clientKey: string; // Your Pngme API key externalId: string; // Your internal user ID companyName: string; // Your company name firstName?: string; lastName?: string; email?: string; phoneNumber?: string; dialogStyle?: PngmeDialogStyle; } interface PngmeDialogStyle { // Colors (hex strings) primaryColor?: string; backgroundColor?: string; textColor?: string; buttonBackgroundColor?: string; buttonTextColor?: string; linkTextColor?: string; // Icon colors closeIconColor?: string; smsIconColor?: string; privacyIconColor?: string; // Text sizes (sp units) titleTextSize?: number; bodyTextSize?: number; buttonTextSize?: number; // Custom text customTitle?: string; customSmsDescription?: string; customPrivacyDescription?: string; customButtonText?: string; // Button styling buttonCornerRadius?: number; buttonElevation?: number; // URLs privacyPolicyUrl?: string; eulaUrl?: string; // Layout contentPadding?: number; } interface PngmePermissionStatus { smsPermission: 'granted' | 'denied' | 'never_asked'; termsAccepted: boolean; } ``` ## 🎨 Complete Example App ```typescript import React, { useState, useEffect } from 'react'; import { StyleSheet, Text, View, Button, TextInput, ScrollView, Alert, } from 'react-native'; import PngmeSDK from 'expo-pngme-sdk'; export default function App() { const [clientKey, setClientKey] = useState(''); const [userId, setUserId] = useState(''); const [status, setStatus] = useState<any>(null); useEffect(() => { checkStatus(); // Set up event listeners const listeners = [ PngmeSDK.addListener('onPermissionGranted', (event) => { Alert.alert('Success', 'Permissions granted!'); setStatus(event.status); }), PngmeSDK.addListener('onSignInComplete', (event) => { setUserId(event.userId); }), PngmeSDK.addListener('onError', (event) => { Alert.alert('Error', event.error); }), ]; return () => listeners.forEach(l => l.remove()); }, []); const checkStatus = async () => { const status = await PngmeSDK.getPermissionStatus(); setStatus(status); }; const initialize = async () => { if (!clientKey) { Alert.alert('Error', 'Please enter your client key'); return; } try { await PngmeSDK.go({ clientKey, externalId: `user_${Date.now()}`, companyName: 'Test Company', firstName: 'Test', lastName: 'User', dialogStyle: { primaryColor: '#007AFF', buttonBackgroundColor: '#007AFF', } }); } catch (error: any) { Alert.alert('Error', error.message); } }; return ( <ScrollView style={styles.container}> <Text style={styles.title}>Pngme SDK Demo</Text> <View style={styles.card}> <Text style={styles.label}>Status</Text> <Text>SMS: {status?.smsPermission || 'Unknown'}</Text> <Text>Terms: {status?.termsAccepted ? 'Yes' : 'No'}</Text> {userId && <Text>User ID: {userId}</Text>} </View> <View style={styles.card}> <Text style={styles.label}>Client Key</Text> <TextInput style={styles.input} value={clientKey} onChangeText={setClientKey} placeholder="Enter your Pngme client key" /> <Button title="Initialize SDK" onPress={initialize} /> </View> </ScrollView> ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#f5f5f5', }, title: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', marginVertical: 20, }, card: { backgroundColor: 'white', padding: 15, borderRadius: 10, marginBottom: 15, }, label: { fontSize: 16, fontWeight: '600', marginBottom: 10, }, input: { borderWidth: 1, borderColor: '#ddd', borderRadius: 5, padding: 10, marginBottom: 10, }, }); ``` ## 🔧 Troubleshooting ### Common Issues and Solutions #### "Module not found" Error ```bash # Clear cache and rebuild expo start -c eas build --clear-cache --platform android ``` #### Permission Dialog Not Showing - Ensure you're testing on a real Android device or emulator - Check that `clientKey` and `externalId` are provided - Verify the app is in the foreground #### SDK Not Initializing - Confirm you've created a development build (not using Expo Go) - Check that the Pngme SDK dependency is correctly configured - Verify your client key is valid #### iOS Platform Error This SDK is **Android-only**. It will not work on iOS devices and will throw appropriate errors. ## 🏗️ Build Configuration ### EAS Build In your `eas.json`: ```json { "build": { "development": { "developmentClient": true, "distribution": "internal", "android": { "buildType": "apk" } }, "preview": { "distribution": "internal" }, "production": {} } } ``` ### Local Build ```bash # Install dependencies npm install # Run on Android expo run:android # Build APK locally expo build:android -t apk ``` ## 📊 Data Collection The SDK collects and processes: - SMS messages (filtered for financial transactions) - Basic device information - User-provided information All data is: - Encrypted in transit - Processed according to privacy regulations - Used solely for credit scoring purposes ## 🔒 Security Best Practices 1. **Store Client Key Securely** ```typescript // Use environment variables import Constants from 'expo-constants'; const CLIENT_KEY = Constants.expoConfig?.extra?.pngmeClientKey; ``` 2. **Validate User Data** ```typescript // Validate before passing to SDK const isValidEmail = (email: string) => /\S+@\S+\.\S+/.test(email); const isValidPhone = (phone: string) => /^\+\d{10,15}$/.test(phone); ``` 3. **Handle Errors Gracefully** ```typescript try { await PngmeSDK.go(config); } catch (error) { // Log to analytics, not console analytics.track('pngme_init_failed', { error }); } ``` **Note:** This SDK requires a valid Pngme client key. Contact [Pngme](https://pngme.com) to get started.