ایکسپو کے ساتھ انٹرپرائز موبائل ایپس بنانا اور مقامی رد عمل
ایکسپو ایک تیز رفتار پروٹو ٹائپنگ ٹول سے ایک جائز انٹرپرائز پلیٹ فارم میں پختہ ہو گیا ہے۔ Expo SDK 52 اور نئے فن تعمیر (Fabric renderer + JSI) کے ساتھ، آپ کراس پلیٹ فارم موبائل ایپس بنا سکتے ہیں جو مقامی ایپس کی کارکردگی اور احساس سے مماثل ہوں — اپنی React ویب ایپلیکیشن کے ساتھ کوڈ کا اشتراک کرتے ہوئے اور iOS اور Android دونوں پر ایک ہی TypeScript کوڈ بیس سے بھیجتے ہیں۔
یہ گائیڈ ان نمونوں کا احاطہ کرتا ہے جو شوق کے پروجیکٹ کو پروڈکشن انٹرپرائز ایپ سے الگ کرتے ہیں: EAS بلڈ کنفیگریشن، پش نوٹیفکیشن انفراسٹرکچر، آف لائن-پہلے ڈیٹا کی مطابقت پذیری، بائیو میٹرک تصدیق، اور ایپ اسٹور جمع کرانے کے ورک فلوز۔
اہم ٹیک ویز
- ایکسپو گو ڈیمو کے لیے ہے۔ EAS بلڈ پروڈکشن کے لیے ہے — پہلے دن سے EAS کے ساتھ شروع کریں۔
- نیا فن تعمیر (فیبرک + JSI) آپٹ ان ہے لیکن کارکردگی کے قابل پیمائش فوائد فراہم کرتا ہے
expo-notificationsکو پیش منظر اور پس منظر دونوں ہینڈلنگ کے لیے محتاط سیٹ اپ کی ضرورت ہے۔- آف لائن سپورٹ کو مطابقت پذیر منطق کے ساتھ مقامی ڈیٹا بیس (WatermelonDB یا SQLite) کی ضرورت ہے
expo-local-authenticationکے ساتھ بایومیٹرک تصدیق کوڈ کی چند سطریں ہیں۔- ڈیپ لنکنگ کے لیے app.json اور آپ کے auth Provider کے کال بیک URLs دونوں میں کنفیگریشن کی ضرورت ہوتی ہے
- TypeScript پاتھ عرفی نام ایکسپو میں
babel-plugin-module-resolverکے ذریعے کام کرتے ہیں- کبھی بھی حساس ڈیٹا کو
AsyncStorageمیں ذخیرہ نہ کریں — ٹوکنز کے لیےexpo-secure-storeاستعمال کریں
پروجیکٹ سیٹ اپ
اگر آپ کسی مقامی ماڈیول کی ضروریات کا اندازہ لگاتے ہیں تو ہر ایکسپو پروجیکٹ کو ننگے ورک فلو (منظم نہیں) کے ساتھ شروع کریں۔ منیجڈ ورک فلو آسان ہے لیکن آپ کو محدود کر دیتا ہے — بعد میں سوئچ کرنے کے لیے باہر نکلنے کی ضرورت ہوتی ہے، جو کہ خلل ڈالنے والا ہے۔
# Create new Expo project
npx create-expo-app@latest MyApp --template
# Or with TypeScript template
npx create-expo-app@latest MyApp -t expo-template-blank-typescript
# Install core enterprise dependencies
npx expo install \
expo-router \
expo-secure-store \
expo-local-authentication \
expo-notifications \
expo-updates \
expo-constants \
@react-navigation/native \
@react-navigation/bottom-tabs \
@tanstack/react-query
expo-router فائل پر مبنی روٹنگ سسٹم جدید طریقہ ہے — یہ Next.js کے ایپ راؤٹر کے نمونوں کی عکاسی کرتا ہے، جس سے ویب اور موبائل کے درمیان سیاق و سباق کی تبدیلی بہت آسان ہو جاتی ہے۔
app.json کنفیگریشن
انٹرپرائز ایپس کو شروع سے ہی محتاط app.json کنفیگریشن کی ضرورت ہے:
{
"expo": {
"name": "ECOSIRE",
"slug": "ecosire-mobile",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#0a0a0a"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.ecosire.mobile",
"buildNumber": "1",
"infoPlist": {
"NSFaceIDUsageDescription": "Use Face ID to securely sign in",
"NSCameraUsageDescription": "Take photos for your profile"
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#0a0a0a"
},
"package": "com.ecosire.mobile",
"versionCode": 1,
"permissions": [
"USE_BIOMETRIC",
"USE_FINGERPRINT",
"RECEIVE_BOOT_COMPLETED",
"VIBRATE"
]
},
"plugins": [
[
"expo-notifications",
{
"icon": "./assets/notification-icon.png",
"color": "#f59e0b",
"sounds": ["./assets/notification.wav"]
}
],
"expo-router",
"expo-secure-store",
"expo-local-authentication"
],
"updates": {
"url": "https://u.expo.dev/YOUR-PROJECT-ID"
},
"runtimeVersion": {
"policy": "sdkVersion"
},
"extra": {
"eas": {
"projectId": "YOUR-PROJECT-ID"
}
}
}
}
EAS تعمیر کنفیگریشن
EAS (Expo Application Services) آپ کی ایپ کو بنانے، جمع کروانے اور اپ ڈیٹ کرنے کا انتظام کرتی ہے۔ اسے eas.json کے ساتھ ترتیب دیں:
{
"cli": {
"version": ">= 10.0.0",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"simulator": true
},
"android": {
"buildType": "apk"
},
"env": {
"API_URL": "http://localhost:3001",
"NODE_ENV": "development"
}
},
"preview": {
"distribution": "internal",
"channel": "preview",
"env": {
"API_URL": "https://staging-api.ecosire.com",
"NODE_ENV": "staging"
}
},
"production": {
"channel": "production",
"autoIncrement": true,
"env": {
"API_URL": "https://api.ecosire.com",
"NODE_ENV": "production"
},
"ios": {
"credentialsSource": "remote"
},
"android": {
"credentialsSource": "remote"
}
}
},
"submit": {
"production": {
"ios": {
"appleId": "[email protected]",
"ascAppId": "YOUR-APP-STORE-CONNECT-APP-ID",
"appleTeamId": "YOUR-TEAM-ID"
},
"android": {
"serviceAccountKeyPath": "./google-service-account.json",
"track": "internal"
}
}
}
}
# Build for different environments
eas build --profile development --platform ios
eas build --profile preview --platform all
eas build --profile production --platform all
# Submit to stores
eas submit --profile production --platform ios
eas submit --profile production --platform android
محفوظ تصدیق
انٹرپرائز ایپس کو کبھی بھی AsyncStorage میں تصدیقی ٹوکن اسٹور نہیں کرنا چاہیے — یہ غیر خفیہ کردہ ہے اور جڑ والے آلات پر دیگر ایپس کے لیے قابل رسائی ہے۔ expo-secure-store استعمال کریں جو Keychain (iOS) اور Keystore (Android) استعمال کرتا ہے:
// lib/auth/token-storage.ts
import * as SecureStore from 'expo-secure-store';
const ACCESS_TOKEN_KEY = 'ecosire_access_token';
const REFRESH_TOKEN_KEY = 'ecosire_refresh_token';
export const tokenStorage = {
async saveTokens(accessToken: string, refreshToken: string) {
await Promise.all([
SecureStore.setItemAsync(ACCESS_TOKEN_KEY, accessToken, {
keychainService: 'com.ecosire.mobile.auth',
keychainAccessible: SecureStore.WHEN_UNLOCKED,
}),
SecureStore.setItemAsync(REFRESH_TOKEN_KEY, refreshToken, {
keychainService: 'com.ecosire.mobile.auth',
keychainAccessible: SecureStore.WHEN_UNLOCKED,
}),
]);
},
async getAccessToken(): Promise<string | null> {
return SecureStore.getItemAsync(ACCESS_TOKEN_KEY, {
keychainService: 'com.ecosire.mobile.auth',
});
},
async getRefreshToken(): Promise<string | null> {
return SecureStore.getItemAsync(REFRESH_TOKEN_KEY, {
keychainService: 'com.ecosire.mobile.auth',
});
},
async clearTokens() {
await Promise.all([
SecureStore.deleteItemAsync(ACCESS_TOKEN_KEY),
SecureStore.deleteItemAsync(REFRESH_TOKEN_KEY),
]);
},
};
بائیو میٹرک تصدیق
فیس آئی ڈی / ٹچ آئی ڈی / فنگر پرنٹ کی توثیق شامل کرنا:
// lib/auth/biometric.ts
import * as LocalAuthentication from 'expo-local-authentication';
export async function isBiometricAvailable(): Promise<boolean> {
const compatible = await LocalAuthentication.hasHardwareAsync();
if (!compatible) return false;
const enrolled = await LocalAuthentication.isEnrolledAsync();
return enrolled;
}
export async function authenticateWithBiometrics(
reason = 'Confirm your identity'
): Promise<boolean> {
const result = await LocalAuthentication.authenticateAsync({
promptMessage: reason,
fallbackLabel: 'Use passcode',
disableDeviceFallback: false,
cancelLabel: 'Cancel',
});
return result.success;
}
// Usage in a component
async function handleSensitiveAction() {
const available = await isBiometricAvailable();
if (available) {
const authenticated = await authenticateWithBiometrics(
'Confirm this transaction'
);
if (!authenticated) return;
}
// Proceed with the action
await processSensitiveOperation();
}
پش اطلاعات
پش نوٹیفیکیشن کے لیے بیک اینڈ انفراسٹرکچر اور احتیاط سے اجازت ہینڈلنگ کی ضرورت ہوتی ہے:
// lib/notifications/setup.ts
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import Constants from 'expo-constants';
import { Platform } from 'react-native';
// Configure how notifications appear when app is in foreground
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
export async function registerForPushNotifications(): Promise<string | null> {
// Push notifications don't work on simulators
if (!Device.isDevice) {
console.warn('Push notifications require a physical device');
return null;
}
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
return null; // User denied permissions
}
// Android requires a notification channel
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#f59e0b',
});
}
const projectId = Constants.expoConfig?.extra?.eas?.projectId;
const token = await Notifications.getExpoPushTokenAsync({ projectId });
return token.data;
}
// hooks/use-push-notifications.ts
import { useEffect, useRef } from 'react';
import { AppState } from 'react-native';
import * as Notifications from 'expo-notifications';
import { registerForPushNotifications } from '@/lib/notifications/setup';
import { updatePushToken } from '@/lib/api/notifications';
export function usePushNotifications() {
const notificationListener = useRef<Notifications.Subscription>();
const responseListener = useRef<Notifications.Subscription>();
useEffect(() => {
// Register and save token to backend
registerForPushNotifications().then((token) => {
if (token) {
updatePushToken(token).catch(console.error);
}
});
// Handle notifications received while app is open
notificationListener.current =
Notifications.addNotificationReceivedListener((notification) => {
console.log('Notification received:', notification);
});
// Handle notification tap
responseListener.current =
Notifications.addNotificationResponseReceivedListener((response) => {
const data = response.notification.request.content.data;
// Navigate based on notification data
handleNotificationNavigation(data);
});
return () => {
notificationListener.current?.remove();
responseListener.current?.remove();
};
}, []);
}
WatermelonDB کے ساتھ آف لائن سپورٹ
انٹرپرائز ایپس کو آف لائن کام کرنے کی ضرورت ہے۔ React Native کے لیے WatermelonDB سب سے زیادہ کارکردگی دکھانے والا مقامی ڈیٹا بیس ہے:
npx expo install @nozbe/watermelondb @nozbe/with-observables
// db/schema.ts
import { appSchema, tableSchema } from '@nozbe/watermelondb';
export const schema = appSchema({
version: 1,
tables: [
tableSchema({
name: 'contacts',
columns: [
{ name: 'server_id', type: 'string', isOptional: true },
{ name: 'name', type: 'string' },
{ name: 'email', type: 'string', isOptional: true },
{ name: 'organization_id', type: 'string' },
{ name: 'synced_at', type: 'number', isOptional: true },
{ name: 'is_deleted', type: 'boolean' },
{ name: 'created_at', type: 'number' },
{ name: 'updated_at', type: 'number' },
],
}),
],
});
// lib/sync/contacts-sync.ts
import { synchronize } from '@nozbe/watermelondb/sync';
import { database } from '@/db';
export async function syncContacts(authToken: string) {
await synchronize({
database,
pullChanges: async ({ lastPulledAt }) => {
const response = await fetch(
`${API_URL}/sync/contacts?since=${lastPulledAt}`,
{
headers: { Authorization: `Bearer ${authToken}` },
}
);
const { changes, timestamp } = await response.json();
return { changes, timestamp };
},
pushChanges: async ({ changes }) => {
await fetch(`${API_URL}/sync/contacts`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ changes }),
});
},
migrationsEnabledAtVersion: 1,
});
}
API ڈیٹا کے لیے TanStack استفسار
TanStack Query React Native میں بالکل اسی طرح کام کرتا ہے جس طرح React ویب ایپس میں ہوتا ہے:
// lib/api/contacts.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { tokenStorage } from '@/lib/auth/token-storage';
async function apiRequest<T>(path: string, options?: RequestInit): Promise<T> {
const token = await tokenStorage.getAccessToken();
const response = await fetch(`${process.env.API_URL}${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
...options?.headers,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
export function useContacts() {
return useQuery({
queryKey: ['contacts'],
queryFn: () => apiRequest<Contact[]>('/contacts'),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}
export function useCreateContact() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateContactDto) =>
apiRequest<Contact>('/contacts', {
method: 'POST',
body: JSON.stringify(data),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['contacts'] });
},
});
}
ایکسپو اپڈیٹس کے ساتھ اوور دی ایئر اپڈیٹس
EAS اپ ڈیٹ ایپ اسٹور کے جائزے کے بغیر جاوا اسکرپٹ بنڈل اپ ڈیٹس فراہم کرتا ہے - بگ فکسز کے لیے اہم:
// hooks/use-app-updates.ts
import { useEffect } from 'react';
import * as Updates from 'expo-updates';
import { Alert } from 'react-native';
export function useAppUpdates() {
useEffect(() => {
async function checkForUpdates() {
if (__DEV__) return; // Skip in development
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
Alert.alert(
'Update Available',
'A new version of the app is ready. Restart to apply.',
[
{ text: 'Later', style: 'cancel' },
{
text: 'Restart Now',
onPress: () => Updates.reloadAsync(),
},
]
);
}
} catch (error) {
// Update check failed — app continues running current version
console.warn('Update check failed:', error);
}
}
checkForUpdates();
}, []);
}
اکثر پوچھے گئے سوالات
میں کب Expo کو ننگے ری ایکٹ مقامی پر منتخب کروں؟
انٹرپرائز ایپس کی اکثریت کے لیے ایکسپو کا انتخاب کریں۔ EAS ماحولیاتی نظام 95% انٹرپرائز کی ضروریات کا احاطہ کرتا ہے — بائیو میٹرک تصدیق، پش نوٹیفیکیشن، ڈیپ لنکنگ، کیمرہ، فائل سسٹم، محفوظ اسٹوریج۔ صرف اس صورت میں جب آپ کو اپنی مرضی کے مطابق مقامی ماڈیولز کی ضرورت ہو جو ایکسپو میں دستیاب نہیں ہے، یا اگر آپ لیجیسی مقامی کوڈ کے ساتھ انضمام کر رہے ہیں، تو ننگے ری ایکٹ مقامی پر جائیں۔ ایکسپو کے ساتھ ترقی کا تجربہ نمایاں طور پر بہتر ہے، اور EAS Build مقامی تعمیرات کی پیچیدگی کو ہینڈل کرتا ہے۔
میں Next.js ویب ایپ اور ایکسپو موبائل ایپ کے درمیان کوڈ کا اشتراک کیسے کروں؟
کاروباری منطق، اقسام اور API کلائنٹس کے لیے مشترکہ پیکجوں کے ساتھ Turborepo monorepo استعمال کریں۔ React Native تمام براؤزر/Node.js APIs کو سپورٹ نہیں کرتا، اس لیے اس بارے میں محتاط رہیں کہ مشترکہ پیکجز میں کیا جاتا ہے۔ ایک پیٹرن جو اچھی طرح سے کام کرتا ہے: اقسام، توثیق اسکیماس (Zod)، اور API کلائنٹ کے افعال کا اشتراک کریں، لیکن UI اجزاء کو الگ رکھیں۔ Next.js 16 کا App Router اور Expo Router دونوں ملتے جلتے ذہنی ماڈلز کے ساتھ فائل پر مبنی روٹنگ کا استعمال کرتے ہیں، جس سے متوازی نفاذ کو برقرار رکھنا آسان ہو جاتا ہے۔
میں تصدیقی کال بیکس کے لیے ڈیپ لنکنگ کو کیسے ہینڈل کروں؟
اپنی URI اسکیم کو app.json میں scheme کے تحت ترتیب دیں (جیسے، "scheme": "ecosire")۔ اپنے تصدیق فراہم کنندہ میں ecosire://auth/callback کو ری ڈائریکٹ URI کے طور پر رجسٹر کریں۔ اپنی ایپ میں آنے والے URLs کو ہینڈل کرنے کے لیے expo-linking استعمال کریں۔ یونیورسل لنکس (iOS) اور ایپ لنکس (Android) کے لیے جو حقیقی URLs کی طرح کام کرتے ہیں، آپ کو اضافی ڈومین کی تصدیق کی ضرورت ہے — apple-app-site-association اور assetlinks.json فائلیں جو آپ کے ڈومین سے پیش کی گئی ہیں۔
EAS میں ایپ ورژن کو ہینڈل کرنے کا بہترین طریقہ کیا ہے؟
"appVersionSource": "remote" کو eas.json میں سیٹ کریں اور پروڈکشن کی تعمیرات کے لیے "autoIncrement": true کو فعال کریں۔ یہ EAS کو خود بخود بلڈ نمبرز کا انتظام کرنے دیتا ہے، دستی طور پر اضافہ کرنا بھول جانے کی عام غلطی کو روکتا ہے۔ اپنا انسانی پڑھنے کے قابل ورژن (1.2.3) کو app.json میں رکھیں اور EAS کو بلڈ نمبر (iOS buildNumber, Android versionCode) کو ہینڈل کرنے دیں۔
میں ترقی میں پش اطلاعات کی جانچ کیسے کروں؟
اپنے آلے کے ایکسپو پش ٹوکن کے ساتھ https://expo.dev/notifications پر ایکسپو کا پش نوٹیفکیشن ٹیسٹنگ ٹول استعمال کریں۔ مقامی ترقی کے لیے، expo-notifications ایک scheduleNotificationAsync فنکشن فراہم کرتا ہے جو بیک اینڈ کے بغیر مقامی اطلاعات کو متحرک کرتا ہے۔ اینڈ ٹو اینڈ ٹیسٹنگ کے لیے، eas build --profile development کے ساتھ ایک ڈیولپمنٹ کلائنٹ بنائیں اور ایک فزیکل ڈیوائس استعمال کریں۔
اگلے اقدامات
ایک انٹرپرائز موبائل ایپ بنانے کے لیے جو قابل بھروسہ، محفوظ، اور پیمانے پر برقرار رکھنے کے لیے فاؤنڈیشن کو درست کرنے کی ضرورت ہے — EAS بلڈ کنفیگریشن، محفوظ ٹوکن اسٹوریج، پش نوٹیفکیشن انفراسٹرکچر، اور آف لائن مطابقت پذیری سب کو پہلے دن سے ہی محتاط سیٹ اپ کی ضرورت ہے۔
ECOSIRE نے ایکسپو کا استعمال کرتے ہوئے 11 اسکرینوں، لامحدود اسکرول، پش نوٹیفیکیشنز، اور EAS تعیناتی کنفیگریشن کے ساتھ پروڈکشن موبائل ایپلیکیشنز بنائے ہیں۔ اگر آپ کو موبائل ڈویلپمنٹ کی مہارت کی ضرورت ہے تو، ہماری ترقیاتی خدمات کو دریافت کریں۔
تحریر
ECOSIRE Research and Development Team
ECOSIRE میں انٹرپرائز گریڈ ڈیجیٹل مصنوعات بنانا۔ Odoo انٹیگریشنز، ای کامرس آٹومیشن، اور AI سے چلنے والے کاروباری حل پر بصیرت شیئر کرنا۔
متعلقہ مضامین
Data Mesh Architecture: Decentralized Data for Enterprise
A comprehensive guide to data mesh architecture—principles, implementation patterns, organizational requirements, and how it enables scalable, domain-driven data ownership.
ECOSIRE vs Big 4 Consultancies: Enterprise Quality, Startup Speed
How ECOSIRE delivers enterprise-grade ERP and digital transformation outcomes without Big 4 pricing, overhead, or timeline bloat. A direct comparison.
Generative AI in Enterprise Applications: Beyond Chatbots
Discover how generative AI is transforming enterprise applications beyond chatbots—from code generation to synthetic data, document intelligence, and process automation.