31/12/2022
Som Android-udvikler støder man ofte på situationer, hvor det er nødvendigt at indhente information om den enhed, applikationen kører på. En af de informationer, der ofte efterspørges, er enhedens eget telefonnummer. Ved første øjekast kan dette virke som en simpel opgave, men virkeligheden er ofte mere kompleks, end man umiddelbart skulle tro. Android-platformen, med sit fokus på brugernes privatliv og sikkerhed, har gjort det vanskeligt at programmatisk tilgå telefonnummeret på en måde, der er 100% pålidelig. Ikke desto mindre er der to primære API'er, der kan bruges til at forsøge at hente denne information: TelephonyManager og SubscriptionManager. I denne dybdegående guide vil vi udforske begge metoder, deres begrænsninger, og hvordan du bedst håndterer dem i dine applikationer.

Det er afgørende at forstå, at selvom disse API'er giver adgang til telefonirelaterede data, er der ingen garanti for, at de altid vil returnere det faktiske telefonnummer. Dette skyldes en række faktorer, herunder hvordan mobiloperatører gemmer information på SIM-kortet, enhedens konfiguration, og Android-versionen.
- Brug af TelephonyManager til at hente telefonnummer
- Brug af SubscriptionManager til at hente telefonnummer
- Sammenligning: TelephonyManager vs. SubscriptionManager
- Udfordringer og Bedste Praksis
- Ofte Stillede Spørgsmål (FAQ)
- Hvorfor returnerer getLine1Number() ofte et tomt resultat?
- Kan jeg altid få telefonnummeret programmatisk på Android?
- Hvad er forskellen mellem TelephonyManager og SubscriptionManager?
- Hvilke tilladelser skal jeg bruge for at hente telefonnummeret?
- Hvad sker der, hvis brugeren nægter READ_PHONE_STATE-tilladelsen?
- Konklusion
Brug af TelephonyManager til at hente telefonnummer
TelephonyManager er den ældste og mest kendte metode til at interagere med Androids telefonisystem. Den har eksisteret siden API-niveau 1 og giver en bred vifte af information om enhedens netværksforbindelse, opkaldstilstand og SIM-kort. For at kunne bruge TelephonyManager skal din applikation først anmode om adgang til telefonitjenesten. Dette gøres ved at kalde Context.getSystemService(Context.TELEPHONY_SERVICE).
Nødvendige tilladelser
Før du kan hente telefonnummeret, skal din applikation have den nødvendige tilladelse. Specifikt skal du tilføje READ_PHONE_STATE-tilladelsen til din AndroidManifest.xml-fil. Denne tilladelse er klassificeret som en 'farlig' tilladelse, hvilket betyder, at for enheder, der kører Android 6.0 (API-niveau 23) eller nyere, skal brugeren eksplicit give tilladelsen under kørsel. Dette er en vigtig del af Androids sikkerhedsmodel, der giver brugerne mere kontrol over deres data.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Uden denne tilladelse vil forsøg på at hente telefonnummeret resultere i en SecurityException eller simpelthen returnere et tomt resultat.
Implementering med TelephonyManager
Når tilladelsen er erklæret, kan du bruge getLine1Number()-metoden fra TelephonyManager til at forsøge at hente telefonnummeret. Her er et eksempel på, hvordan det kan gøres, inklusive håndtering af runtime-tilladelser for moderne Android-versioner:
private String getPhoneNumberWithTelephonyManager() {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager != null) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
return telephonyManager.getLine1Number();
} else {
// Tilladelse er ikke givet, anmod om den eller håndter det.
// For enkelhedens skyld, returner tom streng her.
return "";
}
}
return "";
}Det er afgørende at bemærke den store begrænsning ved getLine1Number(). Denne metode returnerer kun telefonnummeret, hvis det er gemt på SIM-kortet af mobiloperatøren. I praksis er dette desværre sjældent tilfældet for mange operatører og SIM-kort. Ofte vil metoden returnere en tom streng eller null, selvom alle tilladelser er korrekt givet. Dette er ikke en fejl i din kode, men en iboende begrænsning af, hvordan mobilnumre håndteres af netværksudbydere, der ofte ikke gemmer brugerens nummer direkte på SIM-kortet af sikkerheds- eller privatlivshensyn. Derfor er pålidelighed af denne metode meget lav.
Håndtering af Runtime-tilladelser (API 23+)
For at sikre, at din applikation fungerer korrekt på enheder med Android 6.0 (Marshmallow) og nyere, skal du implementere logik for at anmode om READ_PHONE_STATE-tilladelsen under kørsel. Dette involverer typisk følgende trin:
- Kontroller, om tilladelsen allerede er givet ved hjælp af
ContextCompat.checkSelfPermission(). - Hvis ikke, forklar brugeren, hvorfor tilladelsen er nødvendig (valgfrit, men anbefalet for en god brugeroplevelse) ved hjælp af
ActivityCompat.shouldShowRequestPermissionRationale(). - Anmod om tilladelsen ved hjælp af
ActivityCompat.requestPermissions(). - Håndter brugerens svar i
onRequestPermissionsResult()-callback-metoden.
En robust implementering vil altid tjekke for tilladelse, før den forsøger at tilgå følsom information. Hvis tilladelsen nægtes, skal din applikation have en fallback-mekanisme, for eksempel at bede brugeren om manuelt at indtaste telefonnummeret.
Brug af SubscriptionManager til at hente telefonnummer
Med introduktionen af Android 5.1 (API-niveau 22) og support for flere SIM-kort, blev SubscriptionManager API'en introduceret. Denne API er designet til at give adgang til information om de forskellige mobilabonnementer, der er aktive på en multi-SIM-enhed. Selvom den primært er beregnet til at håndtere flere SIM-kort, kan den også give adgang til telefonnummeret, hvis det er tilgængeligt.
Fordele ved SubscriptionManager
SubscriptionManager giver en mere detaljeret oversigt over de individuelle abonnementer. Du kan hente en liste over aktive abonnementer, og for hvert abonnement kan du forsøge at hente information som operatørnavn (getCarrierName()), landekode (getCountryIso()), og selvfølgelig telefonnummeret (getNumber()).

Implementering med SubscriptionManager
For at bruge SubscriptionManager skal du igen have READ_PHONE_STATE-tilladelsen. Her er et eksempel på, hvordan du kan hente information ved hjælp af denne API:
private void getPhoneNumberWithSubscriptionManager() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // API 23+ for runtime permission check
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
SubscriptionManager subscriptionManager = SubscriptionManager.from(getApplicationContext());
List<SubscriptionInfo> activeSubscriptions = subscriptionManager.getActiveSubscriptionInfoList();
if (activeSubscriptions != null) {
for (SubscriptionInfo subscriptionInfo: activeSubscriptions) {
Log.d("PhoneInfo", "Nummer: " + subscriptionInfo.getNumber());
Log.d("PhoneInfo", "Netværk: " + subscriptionInfo.getCarrierName());
Log.d("PhoneInfo", "Land: " + subscriptionInfo.getCountryIso());
}
}
} else {
// Anmod om tilladelse eller håndter det.
}
}
}Ligesom med TelephonyManager.getLine1Number(), er SubscriptionInfo.getNumber() heller ikke garanteret at returnere telefonnummeret. Den samme logik om SIM-kortets lagring og operatørernes praksis gælder her. Dog giver SubscriptionManager dig mulighed for at iterere gennem flere SIM-kort (hvis enheden understøtter det) og potentielt få mere kontekst om abonnementet, selvom selve nummeret forbliver utilgængeligt.
Sammenligning: TelephonyManager vs. SubscriptionManager
For at opsummere forskellene og lighederne mellem de to tilgange, lad os se på en sammenligningstabel:
| Funktion | TelephonyManager | SubscriptionManager |
|---|---|---|
| API-niveau | 1 | 22 |
| Multi-SIM support | Nej (fokuserer på primær linje) | Ja (designet til flere SIM-kort) |
| Pålidelighed for nummer | Lav (afhænger af SIM/operatør) | Lav (afhænger af SIM/operatør, men giver mere kontekst) |
| Yderligere information | Opkaldstilstand, netværkstype, osv. | Operatørnavn, landekode, SIM-slot ID per abonnement |
| Primært formål | Generel telefoniinformation | Håndtering af abonnementer (især multi-SIM) |
Det er tydeligt, at ingen af metoderne tilbyder en fuldstændig idiotsikker måde at hente telefonnummeret på. Begge er underlagt de samme underliggende begrænsninger relateret til, hvor og hvordan mobilnumre gemmes.
Udfordringer og Bedste Praksis
Den største udfordring, når man forsøger at hente et telefonnummer programmatisk på Android, er den lave pålidelighed af de tilgængelige API'er. Dette skyldes primært to grunde:
- SIM-kort lagring: Mange SIM-kort gemmer simpelthen ikke telefonnummeret direkte på kortet. Nummeret er snarere tilknyttet abonnementet på operatørens netværk.
- Privatliv og sikkerhed: Android prioriterer brugernes privatliv. At give apps fri adgang til telefonnumre uden en eksplicit handling fra brugeren ville være en sikkerhedsrisiko.
Anbefalede bedste praksis
På grund af disse begrænsninger er den mest robuste og brugervenlige løsning at implementere en fallback-mekanisme:
- Anmod altid om tilladelse: Sørg for at anmode om
READ_PHONE_STATE-tilladelsen korrekt under kørsel for Android 6.0 og nyere. - Forklar behovet: Hvis din applikation beder om tilladelser, der kan virke invasive, så forklar brugeren, hvorfor du har brug for dem. Dette bygger tillid og øger sandsynligheden for, at tilladelsen gives.
- Implementer brugerinput som fallback: Uanset om du bruger
TelephonyManagerellerSubscriptionManager, bør du altid have en mulighed for, at brugeren manuelt kan indtaste sit telefonnummer, hvis den automatiske hentning mislykkes. Dette er den mest pålidelige måde at opnå nummeret på. Du kan endda forududfylde inputfeltet med det nummer, du eventuelt har hentet, så brugeren blot skal bekræfte. - Håndter afviste tilladelser: Hvis brugeren nægter tilladelsen, skal din applikation ikke crashe eller blive ubrugelig. Giv en klar besked og vejled brugeren til den manuelle indtastningsmulighed.
- Overvej formålet: Stil dig selv spørgsmålet: Har jeg virkelig brug for telefonnummeret? Ofte kan alternative identifikatorer (f.eks. enhedens ID, brugerens Google-konto) bruges, hvis formålet ikke specifikt kræver telefonnummeret.
Ofte Stillede Spørgsmål (FAQ)
Hvorfor returnerer getLine1Number() ofte et tomt resultat?
getLine1Number() returnerer kun telefonnummeret, hvis det er gemt direkte på SIM-kortet. Mange mobiloperatører gemmer ikke længere telefonnummeret på SIM-kortet af sikkerheds- og privatlivshensyn. Nummeret er i stedet gemt i operatørens netværk. Derfor er det almindeligt, at metoden returnerer en tom streng eller null.
Kan jeg altid få telefonnummeret programmatisk på Android?
Nej, det er desværre ikke altid muligt eller pålideligt at hente telefonnummeret programmatisk. Som beskrevet afhænger det af mobiloperatøren og hvordan de konfigurerer SIM-kortet. Den mest pålidelige metode er altid at bede brugeren om at indtaste nummeret manuelt.
Hvad er forskellen mellem TelephonyManager og SubscriptionManager?
TelephonyManager er en ældre API (fra API 1), der giver generel information om enhedens telefoni. SubscriptionManager blev introduceret med API 22 og er specifikt designet til at håndtere information om aktive mobilabonnementer, især på enheder med flere SIM-kort. Mens begge kan forsøge at hente telefonnummeret, giver SubscriptionManager mere kontekst om de individuelle abonnementer (f.eks. operatørnavn, landekode).
Hvilke tilladelser skal jeg bruge for at hente telefonnummeret?
Du skal bruge READ_PHONE_STATE-tilladelsen i din AndroidManifest.xml. For Android 6.0 (API 23) og nyere skal denne tilladelse også anmodes om under kørsel, og brugeren skal eksplicit godkende den.
Hvad sker der, hvis brugeren nægter READ_PHONE_STATE-tilladelsen?
Hvis brugeren nægter READ_PHONE_STATE-tilladelsen, vil din applikation ikke være i stand til at hente telefonnummeret programmatisk. I dette scenarie er det afgørende at have en fallback-mekanisme, f.eks. en brugergrænseflade, hvor brugeren manuelt kan indtaste sit telefonnummer. Din applikation bør ikke crashe, men gracefully håndtere afvisningen.
Konklusion
At hente et telefonnummer programmatisk på Android er en opgave, der er forbundet med visse udfordringer og begrænsninger. Selvom TelephonyManager og SubscriptionManager API'erne giver de nødvendige værktøjer, er pålideligheden af at hente telefonnummeret ofte lav på grund af mobiloperatørernes praksis og Androids fokus på privatliv. Den mest effektive og brugervenlige tilgang er at kombinere forsøg på automatisk hentning med en robust fallback-mekanisme, der tillader brugerinput. Ved at implementere korrekt tilladelseshåndtering og give en god brugeroplevelse kan du bygge applikationer, der er både funktionelle og respekterer brugernes privatliv.
Hvis du vil læse andre artikler, der ligner Sådan henter du et telefonnummer på Android, kan du besøge kategorien Mobiludvikling.
