Geliştiriciler · API v1.0.0

React Native (Bare / CLI) Entegrasyonu

Bu rehber npx @react-native-community/cli init ile oluşturulmuş (Expo olmayan) React Native projeleri içindir. Genel API referansı için Genel bakış dosyasına bakın.

Desteklenen sürümler: React Native 0.74+ (New Architecture dahil) · iOS 13.4+ · Android 7.0+ (API 24) · Node 18+

NotiPilot 1.0.0 teslimatı Expo Push Service üzerinden yaptığı için cihazın bir Expo Push Token'ına ihtiyacı vardır. Bare React Native projesinde bunun iki yolu vardır:

Yöntem Ne zaman?
A. expo-notifications (önerilen) Çoğu proje için. Expo modülleri bare projeye eklenir; Expo'ya geçiş gerektirmez.
B. @react-native-firebase/messaging + token dönüşümü Projede zaten Firebase Messaging kullanılıyorsa.

Her iki yöntemde de bir EAS projesi oluşturmanız (npx eas-cli init) ve FCM V1 / APNs kimlik bilgilerini eas credentials ile yüklemeniz gerekir. EAS proje ID'si, NotiPilot panelindeki Expo Project ID alanına girilen ve API'ye app_id olarak gönderilen değerdir.


Yöntem A — expo-notifications (önerilen)

1. Kurulum

Terminal
npx install-expo-modules@latest
npx expo install expo-notifications expo-device expo-secure-store expo-localization expo-crypto expo-application
cd ios && pod install && cd ..

Android

  1. Firebase konsolundan google-services.json dosyasını indirip android/app/ içine koyun.
  2. android/build.gradle → dependencies { classpath 'com.google.gms:google-services:4.4.2' }
  3. android/app/build.gradle → en alta apply plugin: 'com.google.gms.google-services'

iOS (Xcode → Signing & Capabilities)

  1. Push Notifications capability'sini ekleyin.
  2. Background Modes → Remote notifications seçeneğini işaretleyin.

2. İstemci kodu

Expo rehberindeki src/notipilot.ts dosyasını aynen kullanabilirsiniz. Bare projede expo-constants manifest'i bulunmadığı için yalnızca proje ID'sini sabit olarak verin ve app_version değerini expo-application'dan alın:

TypeScript
import * as Application from 'expo-application';

// NotiPilot panelindeki "Expo Project ID" ile aynı
const PROJECT_ID = 'EAS-PROJE-ID-NIZ';

// registerDevice() içindeki attributes:
//   app_version: Application.nativeApplicationVersion,

Yöntem B — Firebase Messaging + Expo token dönüşümü

Projede @react-native-firebase/messaging zaten kuruluysa, cihazın native token'ını Expo token'ına dönüştürüp NotiPilot'a gönderebilirsiniz.

Terminal
npm i @react-native-firebase/app @react-native-firebase/messaging react-native-get-random-values uuid @react-native-async-storage/async-storage react-native-localize react-native-device-info
TypeScript
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
import messaging from '@react-native-firebase/messaging';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as RNLocalize from 'react-native-localize';
import DeviceInfo from 'react-native-device-info';
import { Platform, PermissionsAndroid } from 'react-native';

const NOTIPILOT_BASE_URL = 'https://app.notipilot.com/api/v1';
const PROJECT_ID = 'EAS-PROJE-ID-NIZ';

async function getDeviceUid() {
  let uid = await AsyncStorage.getItem('notipilot_device_uid');
  if (!uid) {
    uid = uuidv4();
    await AsyncStorage.setItem('notipilot_device_uid', uid);
  }
  return uid;
}

async function requestPermission(): Promise<boolean> {
  if (Platform.OS === 'android' && Platform.Version >= 33) {
    const r = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
    if (r !== PermissionsAndroid.RESULTS.GRANTED) return false;
  }
  const status = await messaging().requestPermission();
  return (
    status === messaging.AuthorizationStatus.AUTHORIZED ||
    status === messaging.AuthorizationStatus.PROVISIONAL
  );
}

/** Native FCM/APNs token'ını Expo Push Token'a dönüştürür. */
async function toExpoPushToken(deviceUid: string): Promise<string> {
  const isIOS = Platform.OS === 'ios';
  const deviceToken = isIOS ? await messaging().getAPNSToken() : await messaging().getToken();
  if (!deviceToken) throw new Error('Native push token alınamadı');

  const res = await fetch('https://exp.host/--/api/v2/push/getExpoPushToken', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      type: isIOS ? 'apns' : 'fcm',
      deviceId: deviceUid.toLowerCase(),
      development: __DEV__ && isIOS, // iOS debug build'leri APNs sandbox kullanır
      appId: DeviceInfo.getBundleId(), // Android package / iOS bundle id
      deviceToken,
      projectId: PROJECT_ID,
    }),
  });
  if (!res.ok) throw new Error(`Expo token dönüşümü başarısız: ${res.status}`);
  const json = await res.json();
  return json.data.expoPushToken; // "ExponentPushToken[...]"
}

export async function registerDevice(extra: Record<string, string | number | boolean | null> = {}) {
  if (!(await requestPermission())) return null;

  const deviceUid = await getDeviceUid();
  const token = await toExpoPushToken(deviceUid);
  const locale = RNLocalize.getLocales()[0];

  const res = await fetch(`${NOTIPILOT_BASE_URL}/register-device`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      app_id: PROJECT_ID,
      device_uid: deviceUid,
      token,
      platform: Platform.OS,
      provider: 'expo',
      attributes: {
        locale: locale?.languageCode ?? null,
        country: RNLocalize.getCountry(),
        app_version: DeviceInfo.getVersion(),
        ...extra,
      },
    }),
  });
  return res.json();
}

// Token yenilendiğinde tekrar kaydedin
messaging().onTokenRefresh(() => registerDevice().catch(() => {}));

exp.host/--/api/v2/push/getExpoPushToken, Expo'nun kendi expo-notifications kütüphanesinin kullandığı endpoint'tir; Expo tarafından ayrıca dokümante edilmemiştir. Uzun vadeli en güvenli seçenek Yöntem A'dır.

identify-device çağrısı ve hata yönetimi için Expo rehberindeki identify, logout ve post fonksiyonlarını aynen kullanabilirsiniz.

Kontrol listesi

  • EAS projesi oluşturuldu, proje ID'si panelde Expo Project ID olarak girildi
  • eas credentials ile FCM V1 + APNs kimlik bilgileri yüklendi
  • Android 13+ için POST_NOTIFICATIONS izni isteniyor
  • iOS'ta Push Notifications + Remote notifications capability'leri açık
  • country ve mümkünse city attributes olarak gönderiliyor