Aller au contenu principal

Guide de l'API SMS Retriever

Apprenez à implémenter l'API SMS Retriever d'Android pour la consommation automatique de SMS dans les applications Flutter, React Native et Kotlin.

Vue d'ensemble

L'API SMS Retriever d'Android permet à votre application de lire automatiquement les messages SMS contenant une chaîne de hachage spécifique de 11 caractères. Cela permet une vérification OTP transparente et d'autres flux d'authentification basés sur SMS sans nécessiter d'autorisations de lecture SMS.

Lorsque vous incluez un hash dans votre requête OTP de SMS Gateway (POST /otp/send), le hash sera automatiquement ajouté à votre message OTP sur une nouvelle ligne, le rendant compatible avec l'API SMS Retriever.

Comment ça fonctionne

  1. Générer le Hash : Votre application génère un hash de 11 caractères basé sur le nom du package et le certificat de signature de votre application
  2. Envoyer le SMS : Incluez le hash dans votre requête API SMS Gateway
  3. Consommation automatique : Android lit automatiquement les messages SMS contenant votre hash
  4. Recevoir le SMS : Votre application reçoit le contenu du SMS sans interaction utilisateur

Format du Hash

  • Longueur : Exactement 11 caractères
  • Caractères : Alphanumériques (A-Z, a-z, 0-9)
  • Exemple : ABC123XYZ45
  • Séparateur : Le hash est automatiquement ajouté sur une nouvelle ligne après votre message

Exemple : Si vous envoyez message: "Your code is: 123456" avec hash: "ABC123XYZ45", le SMS résultant sera :

Your code is: 123456
ABC123XYZ45

Guides d'implémentation

Flutter

Utilisation du package sms_autofill

  1. Ajouter la dépendance dans pubspec.yaml :
dependencies:
sms_autofill: ^2.3.0
  1. Obtenir le hash :
import 'package:sms_autofill/sms_autofill.dart';

class SmsRetrieverExample {
Future<String?> getAppSignature() async {
try {
final signature = await SmsAutoFill().getAppSignature;
return signature;
} catch (e) {
print('Erreur lors de l\'obtention de la signature de l\'application : $e');
return null;
}
}
}
  1. Écouter les SMS :
import 'package:sms_autofill/sms_autofill.dart';

class OtpVerificationScreen extends StatefulWidget {
@override
_OtpVerificationScreenState createState() => _OtpVerificationScreenState();
}

class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
String? _code;
final SmsAutoFill _autoFill = SmsAutoFill();

@override
void initState() {
super.initState();
_listenForSms();
}

void _listenForSms() {
_autoFill.listenForCode();
}

@override
Widget build(BuildContext context) {
return PinFieldAutoFill(
codeLength: 6,
onCodeSubmitted: (code) {
setState(() {
_code = code;
});
// Vérifier l'OTP avec votre backend
_verifyOtp(code);
},
);
}

Future<void> _verifyOtp(String code) async {
// Envoyer une requête de vérification à votre backend
final response = await http.post(
Uri.parse('https://your-api.com/otp/verify'),
body: jsonEncode({
'phoneNumber': '+1234567890',
'otp': code,
}),
);
}

@override
void dispose() {
_autoFill.unregisterListener();
super.dispose();
}
}
  1. Envoyer un SMS avec hash :
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<void> sendOtpWithHash(String phoneNumber) async {
// Obtenir la signature de l'application (hash)
final signature = await SmsAutoFill().getAppSignature;

// Envoyer un SMS via l'API SMS Gateway
final response = await http.post(
Uri.parse('https://sms.chinqit.com/messages/send'),
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'YOUR_API_KEY',
},
body: jsonEncode({
'phoneNumber': phoneNumber,
'message': 'Your verification code is: 123456',
'hash': signature, // Inclure le hash
}),
);

if (response.statusCode == 200) {
print('SMS envoyé avec succès');
}
}

Utilisation du package sms_retriever (Alternative)

dependencies:
sms_retriever: ^1.0.0
import 'package:sms_retriever/sms_retriever.dart';

Future<String?> getAppSignature() async {
try {
final signature = await SmsRetriever.getAppSignature();
return signature;
} catch (e) {
print('Erreur : $e');
return null;
}
}

void listenForSms() {
SmsRetriever.listenForSms().listen((sms) {
// Extraire l'OTP du SMS
final otp = extractOtp(sms);
// Vérifier l'OTP
verifyOtp(otp);
});
}

String extractOtp(String sms) {
// Extraire un OTP de 6 chiffres du SMS
final regex = RegExp(r'\b\d{6}\b');
final match = regex.firstMatch(sms);
return match?.group(0) ?? '';
}

React Native

Utilisation de react-native-sms-retriever

  1. Installer le package :
npm install react-native-sms-retriever
# ou
yarn add react-native-sms-retriever
  1. Lier le package (pour les anciennes versions de React Native) :
cd ios && pod install
  1. Obtenir le hash :
import SmsRetriever from "react-native-sms-retriever";

class SmsRetrieverExample {
async getAppSignature() {
try {
const hash = await SmsRetriever.getAppHash();
return hash;
} catch (error) {
console.error("Erreur lors de l'obtention du hash de l'application :", error);
return null;
}
}
}
  1. Écouter les SMS :
import SmsRetriever from "react-native-sms-retriever";
import { useEffect, useState } from "react";

function OtpVerificationScreen() {
const [otp, setOtp] = useState("");

useEffect(() => {
// Commencer à écouter les SMS
SmsRetriever.startSmsRetriever()
.then(() => {
console.log("SMS Retriever démarré");
})
.catch((error) => {
console.error("Erreur lors du démarrage de SMS Retriever :", error);
});

// Écouter les SMS
const subscription = SmsRetriever.addSmsListener((event) => {
const message = event.message;
// Extraire l'OTP du message
const extractedOtp = extractOtp(message);
if (extractedOtp) {
setOtp(extractedOtp);
verifyOtp(extractedOtp);
}
});

return () => {
// Nettoyage
subscription.remove();
SmsRetriever.removeSmsListener();
};
}, []);

const extractOtp = (message) => {
// Extraire un OTP de 6 chiffres
const match = message.match(/\b\d{6}\b/);
return match ? match[0] : null;
};

const verifyOtp = async (code) => {
try {
const response = await fetch("https://your-api.com/otp/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
phoneNumber: "+1234567890",
otp: code,
}),
});
const data = await response.json();
if (data.verified) {
console.log("OTP vérifié avec succès");
}
} catch (error) {
console.error("Erreur lors de la vérification de l'OTP :", error);
}
};

return (
<View>
<Text>Entrer l'OTP : {otp}</Text>
</View>
);
}
  1. Envoyer un SMS avec hash :
import SmsRetriever from "react-native-sms-retriever";

async function sendOtpWithHash(phoneNumber) {
try {
// Obtenir le hash de l'application
const hash = await SmsRetriever.getAppHash();

// Envoyer un SMS via l'API SMS Gateway
const response = await fetch("https://sms.chinqit.com/messages/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "YOUR_API_KEY",
},
body: JSON.stringify({
phoneNumber: phoneNumber,
message: "Your verification code is: 123456",
hash: hash, // Inclure le hash
}),
});

const data = await response.json();
if (data.success) {
console.log("SMS envoyé avec succès");
}
} catch (error) {
console.error("Erreur lors de l'envoi du SMS :", error);
}
}

Utilisation de react-native-otp-verify (Alternative)

npm install react-native-otp-verify
import OtpVerify from "react-native-otp-verify";

// Obtenir le hash
OtpVerify.getHash()
.then((hash) => {
console.log("Hash :", hash);
})
.catch((error) => {
console.error("Erreur :", error);
});

// Écouter les SMS
OtpVerify.getOtp()
.then((message) => {
// Extraire l'OTP du message
const otp = extractOtp(message);
verifyOtp(otp);
})
.catch((error) => {
console.error("Erreur :", error);
});

Kotlin (Android natif)

Étapes d'implémentation

  1. Ajouter la dépendance dans build.gradle.kts :
dependencies {
implementation("com.google.android.gms:play-services-auth-api-phone:18.0.1")
}
  1. Obtenir le hash :
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.auth.api.phone.SmsRetrieverClient
import com.google.android.gms.tasks.Task

class SmsRetrieverHelper(private val context: Context) {

fun getAppSignatureHash(callback: (String?) -> Unit) {
val client: SmsRetrieverClient = SmsRetriever.getClient(context)
val task: Task<String> = client.smsRetrieverClient.startSmsRetriever()

task.addOnSuccessListener { result ->
// Le hash est retourné dans le résultat
// Note : Cette méthode ne retourne pas directement le hash
// Vous devez utiliser l'API SMS Retriever différemment
callback(null)
}

task.addOnFailureListener { e ->
callback(null)
}
}

// Alternative : Obtenir le hash en utilisant la réflexion (pour les tests)
fun getAppSignatureHashString(): String? {
return try {
val info = context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNATURES
)
val signatures = info.signatures
if (signatures.isNotEmpty()) {
val signature = signatures[0]
val md = MessageDigest.getInstance("SHA-256")
md.update(signature.toByteArray())
val hashBytes = md.digest()
// Convertir en base64 et prendre les 11 premiers caractères
Base64.encodeToString(hashBytes, Base64.NO_WRAP)
.substring(0, 11)
.replace("+", "A")
.replace("/", "B")
.replace("=", "C")
} else {
null
}
} catch (e: Exception) {
null
}
}
}
  1. Écouter les SMS :
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.auth.api.phone.SmsRetrieverClient
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status

class SmsRetrieverReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
val extras = intent.extras
val status = extras?.get(SmsRetriever.EXTRA_STATUS) as? Status

when (status?.statusCode) {
CommonStatusCodes.SUCCESS -> {
// Obtenir le message SMS
val message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE)
message?.let {
// Extraire l'OTP du message
val otp = extractOtp(it)
otp?.let { code ->
// Vérifier l'OTP
verifyOtp(code)
}
}
}
CommonStatusCodes.TIMEOUT -> {
// Délai d'attente dépassé pour le SMS
}
}
}
}

private fun extractOtp(message: String): String? {
// Extraire un OTP de 6 chiffres
val regex = Regex("\\b\\d{6}\\b")
return regex.find(message)?.value
}

private fun verifyOtp(otp: String) {
// Envoyer une requête de vérification à votre backend
// L'implémentation dépend de votre bibliothèque réseau
}
}
  1. Démarrer SMS Retriever :
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.auth.api.phone.SmsRetrieverClient

class MainActivity : AppCompatActivity() {

private lateinit var smsRetrieverReceiver: BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Enregistrer le récepteur SMS Retriever
smsRetrieverReceiver = SmsRetrieverReceiver()
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
registerReceiver(smsRetrieverReceiver, intentFilter)

// Démarrer SMS Retriever
startSmsRetriever()
}

private fun startSmsRetriever() {
val client: SmsRetrieverClient = SmsRetriever.getClient(this)
val task = client.startSmsRetriever()

task.addOnSuccessListener {
// SMS Retriever démarré avec succès
Log.d("SMS", "SMS Retriever démarré")
}

task.addOnFailureListener { e ->
Log.e("SMS", "Échec du démarrage de SMS Retriever", e)
}
}

override fun onDestroy() {
super.onDestroy()
unregisterReceiver(smsRetrieverReceiver)
}
}
  1. Envoyer un SMS avec hash :
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

class SmsService(private val context: Context) {

private val client = OkHttpClient()

suspend fun sendOtpWithHash(phoneNumber: String, message: String) {
// Obtenir le hash
val hash = getAppSignatureHashString()

// Préparer la requête
val json = JSONObject().apply {
put("phoneNumber", phoneNumber)
put("message", message)
hash?.let { put("hash", it) }
}

val requestBody = json.toString()
.toRequestBody("application/json".toMediaType())

val request = Request.Builder()
.url("https://sms.chinqit.com/messages/send")
.post(requestBody)
.addHeader("Content-Type", "application/json")
.addHeader("X-API-Key", "YOUR_API_KEY")
.build()

try {
val response = client.newCall(request).execute()
if (response.isSuccessful) {
Log.d("SMS", "SMS envoyé avec succès")
}
} catch (e: Exception) {
Log.e("SMS", "Erreur lors de l'envoi du SMS", e)
}
}

private fun getAppSignatureHashString(): String? {
// Implémentation de l'étape 2
return SmsRetrieverHelper(context).getAppSignatureHashString()
}
}

Notes importantes

  1. Génération du Hash : Le hash est généré en fonction du nom du package de votre application et du certificat de signature. Il sera différent pour les builds de débogage et de production.

  2. Format du SMS : Le SMS doit commencer par la chaîne de hash. Notre API ajoute le hash à la fin de votre message, assurez-vous donc que le format de votre message fonctionne avec cela.

  3. Tests : Utilisez le SMS Retriever API Playground pour tester la génération de votre hash.

  4. Autorisations : Aucune autorisation de lecture SMS n'est requise. L'API SMS Retriever gère la lecture des SMS automatiquement.

  5. Délai d'attente : L'API SMS Retriever a un délai d'attente de 5 minutes. Si aucun SMS n'est reçu dans ce délai, vous devrez redémarrer le retriever.

Dépannage

Le Hash ne fonctionne pas

  • Vérifiez que votre hash compte exactement 11 caractères
  • Assurez-vous d'utiliser le bon certificat de signature (debug vs release)
  • Vérifiez que le format du SMS correspond aux exigences d'Android

SMS non reçu

  • Vérifiez que le hash correspond à la signature de votre application
  • Assurez-vous que SMS Retriever est démarré avant d'envoyer le SMS
  • Vérifiez que le SMS contient la chaîne de hash

Problèmes de délai d'attente

  • Redémarrez SMS Retriever si un délai d'attente se produit
  • Implémentez une logique de réessai pour les tentatives échouées
  • Envisagez un repli vers la saisie manuelle de l'OTP

Ressources supplémentaires


Besoin d'aide ? Consultez la Référence API ou le Guide de dépannage pour plus d'informations.