以编程方式获取Android手机的电话号码


443

如何以编程方式获取运行我的android应用的设备的电话号码?


这是不可能的,除非您自己输入。电话号码不被移动或SIM卡,只能通过网络知道....
tomsoft

3
@tomsoft考虑一下... Facebook之类的应用程序如何自动神奇地验证您的电话号码..?
Eddie Hart

1
@tomsoft不,在大多数情况下,它甚至不询问您的电话号码,或者如果确实要求,则预填充该框。
艾迪·哈特

1
@tomsoft好吧,前几天我注册了Facebook,当它向我发送代码时,它并没有询问我的电话号码。尝试一下。;)
Eddie Hart

1
@EddieHart也可以,我也被问到我的电话号码。因此,这可以确认,一般而言,这是无法访问的,并且某些操作员可能会在安装时添加此信息,但这不是GMS标准功能
tomsoft

Answers:


484

码:

TelephonyManager tMgr = (TelephonyManager)mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
String mPhoneNumber = tMgr.getLine1Number();

所需权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/> 

注意事项:

根据高度评价的评论,有一些注意事项需要注意。这可以返回null""什至"???????",它可以返回不再有效的陈旧电话号码。如果您想要唯一标识设备的信息,则应getDeviceId()改用。


150
实际上,并不是那么完美。上次尝试此方法时,它报告了我的手机原来的电话号码,然后才将旧的手机号码移植到该电话上。可能仍会这样做,因为“设置”应用程序仍会显示该无效数字。另外,有报告说某些SIM卡导致此方法返回null。话虽这么说,我不知道一个更好的答案。
CommonsWare 2010年

4
马克说得对。如果要使用可唯一标识电话的内容,则可以使用getDeviceId(),它将为GSM返回IMEA。
Alex Volovoy 2010年

15
(我想您是说IMEI ...?)
ChaimKut 2011年

23
好吧,我在装有Android OS 2.2的Nexus One上进行了测试,结果返回null
Omar Rehman

43
通过考虑投票数,开发人员可能认为这是完美的答案。应该添加注释以警告开发人员此方法不会始终提供电话号码。
Habeeb Perwad 2014年

151

无法保证解决此问题的方法,因为电话号码并未物理存储在所有SIM卡上,也未从网络广播到电话中。在某些需要物理地址验证的国家中尤其如此,编号分配仅在此之后进行。电话号码分配发生在网络上-可以在不更改SIM卡或设备的情况下进行更改(例如,这是支持端口的方式)。

我知道这很痛苦,但是最好的解决方案很可能就是要求用户输入一次他/她的电话号码并进行存储。


18
为了验证接收的号码,您可以向该号码发送短信(包含代码),并通过将侦听器置于“ android.provider.Telephony.SMS_RECEIVED”上来控制响应。这样可以确保该号码是正确的,工作
侯赛因Shahdoost

1
创造性的解决方案,但您可能想让用户知道您正在这样做,以防万一他们为此付费。
Norman H

3
是否有任何供应商,接受简单的短信费?
ThiefMaster 2014年

9
是的,一点没错。在将短信添加到计划中之前,我需要为每条收到的短信支付0.30美元。罗杰斯在加拿大。
约翰·克罗奇

44

更新:该答案不再可用,因为Whatsapp已停止将电话号码公开为帐户名,请忽略此答案。

如果您无法通过电话服务获得解决方案,则实际上可能需要考虑其他解决方案。

从今天起,您可以使用依靠另一个大型应用程序Whatsapp AccountManager。数以百万计的设备已安装了此应用程序,如果您无法通过获得电话号码TelephonyManager,可以尝试一下。

允许:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

码:

AccountManager am = AccountManager.get(this);
Account[] accounts = am.getAccounts();

for (Account ac : accounts) {
    String acname = ac.name;
    String actype = ac.type;
    // Take your time to look at all available accounts
    System.out.println("Accounts : " + acname + ", " + actype);
}

检查actypeWhatsApp帐户

if(actype.equals("com.whatsapp")){
    String phoneNumber = ac.name;
}

当然,如果用户未安装WhatsApp,则可能无法获得它,但还是值得尝试的。请记住,您应该始终向用户询问确认信息。


1
我今天在弄乱帐户时才看到此消息。如此暴露数字是非常糟糕的。当然,您需要GET_ACCOUNTS权限,此时用户可能不在乎应用程序具有什么权限。
jargetz 2014年

9
该解决方案已过时,Whatsapp不再将电话号码保存在帐户名称上,您知道新更新后whatsapp在哪里保存电话号码吗?
Cohelad 2014年

@Cohelad感谢您更新我,稍后我将进行检查,并在确认后清除此答案,与此同时,我不知道他们将号码保存在哪里
Chor Wai Chun 2014年

3
但是Viber公开了这个数字!com.viber.voip.account
xnagyg 2015年

32

如我先前的答案中所述

使用以下代码:

TelephonyManager tMgr = (TelephonyManager)mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
String mPhoneNumber = tMgr.getLine1Number();

在AndroidManifest.xml中,授予以下权限:

 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 

但是请记住,此代码并不总是有效,因为手机号码取决于SIM卡和网络运营商/手机运营商。

另外,请尝试在“ 电话”->“设置”->“关于”->“电话身份”中签入,如果您能够在那里查看“号码”,则从上述代码获取电话号码的可能性更高。如果您无法在设置中查看电话号码,则无法通过此代码获取!

建议的解决方法:

  1. 从用户那里获取用户的电话号码作为手动输入。
  2. 通过短信将代码发送到用户的手机号码。
  3. 要求用户输入代码以确认电话号码。
  4. 将数字保存在sharedpreference中。

在应用程序首次启动期间,将上述4个步骤作为一次活动进行。以后,每当需要电话号码时,请使用共享首选项中的可用值。


这个答案涵盖了所有因素,应该被接受为一个=)
Slava Fomin II

如果手机上有双SIM卡,我如何获得两个手机号码。以上代码。对于单SIM卡,它的工作效果很好
Amrit Chakradhari,

26

因此,这就是您未经许可和黑客就通过Play Services API请求电话号码的方式。源代码完整示例

在您的build.gradle中(要求版本10.2.x及更高版本):

compile "com.google.android.gms:play-services-auth:$gms_version"

在您的活动中(简化了代码):

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...
    googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Auth.CREDENTIALS_API)
            .build();
    requestPhoneNumber(result -> {
        phoneET.setText(result);
    });
}

public void requestPhoneNumber(SimpleCallback<String> callback) {
    phoneNumberCallback = callback;
    HintRequest hintRequest = new HintRequest.Builder()
            .setPhoneNumberIdentifierSupported(true)
            .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(googleApiClient, hintRequest);
    try {
        startIntentSenderForResult(intent.getIntentSender(), PHONE_NUMBER_RC, null, 0, 0, 0);
    } catch (IntentSender.SendIntentException e) {
        Logs.e(TAG, "Could not start hint picker Intent", e);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PHONE_NUMBER_RC) {
        if (resultCode == RESULT_OK) {
            Credential cred = data.getParcelableExtra(Credential.EXTRA_KEY);
            if (phoneNumberCallback != null){
                phoneNumberCallback.onSuccess(cred.getId());
            }
        }
        phoneNumberCallback = null;
    }
}

这将生成一个对话框,如下所示:

在此处输入图片说明


2
提示请求会显示来自与手机相连的电子邮件帐户中的电话号码,即使设备中没有SIM卡,它也会显示下拉列表。
阿里(Ari)

当只有一个SIM卡时,对话框如何显示多个数字?对我来说,它显示5个数字。:/ :)
cgr

我们如何在android中自动选择第一个电话号码?
Noorul

13
private String getMyPhoneNumber(){
    TelephonyManager mTelephonyMgr;
    mTelephonyMgr = (TelephonyManager)
        getSystemService(Context.TELEPHONY_SERVICE); 
    return mTelephonyMgr.getLine1Number();
}

private String getMy10DigitPhoneNumber(){
    String s = getMyPhoneNumber();
    return s != null && s.length() > 2 ? s.substring(2) : null;
}

来自http://www.androidsnippets.com/get-my-phone-number的代码


@JaredBurrows是因为“ s.substring(2)”。
Cookie怪物

1
它对我不起作用。我得到一个NULL值(瑞士的日出SIM卡)
电子自然

您的链接已断开。
Ümañgßürmån

11

有一个新的Android API,允许用户在不需要许可的情况下选择他们的电话号码。看一下:https : //android-developers.googleblog.com/2017/10/effective-phone-number-verification.html

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
       .setPhoneNumberIdentifierSupported(true)
       .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
        apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
        RESOLVE_HINT, null, 0, 0, 0);
} 

这需要Firebase
Vlad

@Vlad不,不是。这仅需要大多数设备附带的Google Play服务。引用博客文章中的话:“开始之前,您需要构建并测试该设备,该设备的电话号码可以接收SMS并运行Google Play服务10.2.x及更高版本。”
旋转

9

只是想在以上答案的以上说明中添加一些内容。这也将为他人节省时间。

在我的情况下,此方法未返回任何手机号码,返回了一个空字符串。由于这种情况,我将自己的号码移植到了新的SIM卡上。因此,如果我进入“设置”>“关于电话”>“状态”>“我的电话号码”,则会显示“未知”。


我的也是,这是什么情况?漫游?也许Simcard只是没有存储数字。
亚历山德拉·马孔德斯

8

有时,下面的代码返回null或空白字符串。

TelephonyManager tMgr = (TelephonyManager)mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
String mPhoneNumber = tMgr.getLine1Number();

经以下许可

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

您还有另一种方式可以获取您的电话号码,我没有在多台设备上对此进行测试,但是上述代码并非每次都有效。

试试下面的代码:

String main_data[] = {"data1", "is_primary", "data3", "data2", "data1", "is_primary", "photo_uri", "mimetype"};
Object object = getContentResolver().query(Uri.withAppendedPath(android.provider.ContactsContract.Profile.CONTENT_URI, "data"),
        main_data, "mimetype=?",
        new String[]{"vnd.android.cursor.item/phone_v2"},
        "is_primary DESC");
if (object != null) {
    do {
        if (!((Cursor) (object)).moveToNext())
            break;
        // This is the phoneNumber
        String s1 = ((Cursor) (object)).getString(4);
    } while (true);
    ((Cursor) (object)).close();
}

您将需要添加这两个权限。

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />

希望这会有所帮助,谢谢!


我可以问一下:在第二个片段中,哪个是手机号码?
iOSAndroidWindowsMo​​bileAppsDev

1
的值为String s1电话号码。
activesince93

此代码对我不起作用。(您的最后一个代码段)。返回空字符串。
克里斯蒂·威尔士

请解释您的答案。数字存储在哪里,它如何包含数字?取决于什么?
not2qubit

3
@ not2qubit我认为它正在访问“ 联系人”应用程序中的自我联系人
Samplasion

4

这是一个更简化的答案:

public String getMyPhoneNumber()
{
    return ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
            .getLine1Number();
}

3

首先,让用户使用手机号码违反道德政策,但早前有可能这样做,但现在根据我的研究,尚无可靠的解决方案。通过使用某些代码,可以获取手机号码,但不能保证一定可以使用仅在少数设备中。经过大量研究,我发现只有三种解决方案,但它们不能在所有设备上正常工作。

我们没有得到的原因如下。

1.Android设备和新的SIM卡不存储手机号,如果设备和SIM卡中没有手机号,那么如何获取号码,如果有旧的SIM卡具有手机号,那么使用电话管理器我们可以获取其他号码明智的做法是返回“ null”或“”或“ ??????”

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

 TelephonyManager tel= (TelephonyManager)this.getSystemService(Context.
            TELEPHONY_SERVICE);
    String PhoneNumber =  tel.getLine1Number();

注意:-我已经在以下设备上测试了该解决方案:Moto x,Samsung Tab 4,Samsung S4,Nexus 5和Redmi 2 prime,但是每次返回空字符串时它都不起作用,因此得出结论,它是无用的

  1. 该方法仅在Redmi 2 prime中有效,但是为此需要在清单中添加读取联系人权限。

注意:-这也不是保证有效的解决方案,我已经在很多设备上测试了该解决方案,但是它只能在Redmi 2 prime(这是双SIM卡设备)中工作,它给我两个手机号码第一个是正确的,但是第二个不是属于我的第二张SIM卡,属于我未使用的一些旧SIM卡。

 String main_data[] = {"data1", "is_primary", "data3", "data2", "data1",
            "is_primary", "photo_uri", "mimetype"};
    Object object = getContentResolver().
            query(Uri.withAppendedPath(android.provider.ContactsContract.Profile.CONTENT_URI, "data"),
            main_data, "mimetype=?",
            new String[]{"vnd.android.cursor.item/phone_v2"},
            "is_primary DESC");
    String s1="";
    if (object != null) {
        do {
            if (!((Cursor) (object)).moveToNext())
                break;
            // This is the phoneNumber
             s1 =s1+"---"+ ((Cursor) (object)).getString(4);
        } while (true);
        ((Cursor) (object)).close();
    }
  1. 在我的研究中,我发现较早时可以使用WhatsApp帐户获取手机号码,但是现在新的Whatsapp版本不再存储用户的手机号码。

结论:-Android没有任何保证性的解决方案来以编程方式获取用户的手机号码。

建议:-1.如果要验证用户的手机号码,然后要求用户提供其手机号码,则可以使用otp进行验证。

  1. 如果要标识用户的设备,则可以轻松获取设备的IMEI号。

2

TelephonyManager不是正确的解决方案,因为在某些情况下,该号码未存储在SIM卡中。我建议您应该在首次打开应用程序时使用共享首选项来存储用户的电话号码,并且该号码将在需要时使用。


1
但是这种方法容易出错,用户可以输入错误的号码。
Zohra Khan 2014年

3
是的,为此,我使用了一条短信,当用户输入一个数字时,因此从SmsManager发出该应用消息本身,然后我们可以使用smsReciever获取原始号码
Naveed Ahmad

1
我还有一个问题..用这种方法,用户会给SMS收费(如果这不是免费电话号码)..还有其他方法可以使我获得用户的电话号码吗?
Zohra Khan 2014年

是的,当然,如果该号码不是免费电话号码,则该SMS会收取一些费用。
Naveed Ahmad 2014年

不,我认为到目前为止,没有TelephonyManager就是没有这样的方法。我在回答中指出了TelephoneManager的问题。
Naveed Ahmad 2014年

2

这是我找到的解决方案的组合(如果您还想检查自动填充,请在此处查看示例项目):

表现

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

build.gradle

    implementation "com.google.android.gms:play-services-auth:17.0.0"

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var googleApiClient: GoogleApiClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tryGetCurrentUserPhoneNumber(this)
        googleApiClient = GoogleApiClient.Builder(this).addApi(Auth.CREDENTIALS_API).build()
        if (phoneNumber.isEmpty()) {
            val hintRequest = HintRequest.Builder().setPhoneNumberIdentifierSupported(true).build()
            val intent = Auth.CredentialsApi.getHintPickerIntent(googleApiClient, hintRequest)
            try {
                startIntentSenderForResult(intent.intentSender, REQUEST_PHONE_NUMBER, null, 0, 0, 0);
            } catch (e: IntentSender.SendIntentException) {
                Toast.makeText(this, "failed to show phone picker", Toast.LENGTH_SHORT).show()
            }
        } else
            onGotPhoneNumberToSendTo()

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_PHONE_NUMBER) {
            if (resultCode == Activity.RESULT_OK) {
                val cred: Credential? = data?.getParcelableExtra(Credential.EXTRA_KEY)
                phoneNumber = cred?.id ?: ""
                if (phoneNumber.isEmpty())
                    Toast.makeText(this, "failed to get phone number", Toast.LENGTH_SHORT).show()
                else
                    onGotPhoneNumberToSendTo()
            }
        }
    }

    private fun onGotPhoneNumberToSendTo() {
        Toast.makeText(this, "got number:$phoneNumber", Toast.LENGTH_SHORT).show()
    }


    companion object {
        private const val REQUEST_PHONE_NUMBER = 1
        private var phoneNumber = ""

        @SuppressLint("MissingPermission", "HardwareIds")
        private fun tryGetCurrentUserPhoneNumber(context: Context): String {
            if (phoneNumber.isNotEmpty())
                return phoneNumber
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val subscriptionManager = context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                try {
                    subscriptionManager.activeSubscriptionInfoList?.forEach {
                        val number: String? = it.number
                        if (!number.isNullOrBlank()) {
                            phoneNumber = number
                            return number
                        }
                    }
                } catch (ignored: Exception) {
                }
            }
            try {
                val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                val number = telephonyManager.line1Number ?: ""
                if (!number.isBlank()) {
                    phoneNumber = number
                    return number
                }
            } catch (e: Exception) {
            }
            return ""
        }
    }
}

请在实施此方法之前查看此答案stackoverflow.com/a/48210130/5457916上的评论
humble_wolf

您提供的链接只是我在这里所做的一部分。在这里,我首先尝试自己自动填充。并为此退后一步。
android开发人员

我知道先生,您的回答很好,在任何意义上都不是错误的,我只是想让读者知道这种方式所带来的条件,例如,这可以填充与您的Google帐户相关联的数字,如评论中提到的那样。
humble_wolf

我仍然喜欢我写的东西。抱歉
android开发人员

1

一点贡献。就我而言,代码启动了一个错误异常。我需要添加一个注释,以便代码可以运行并解决该问题。在这里,我让这段代码。

public static String getLineNumberPhone(Context scenario) {
    TelephonyManager tMgr = (TelephonyManager) scenario.getSystemService(Context.TELEPHONY_SERVICE);
    @SuppressLint("MissingPermission") String mPhoneNumber = tMgr.getLine1Number();
    return mPhoneNumber;
}

0

尽管可能有多个语音邮件帐户,但使用您自己的号码拨打电话时,运营商会将您转接到语音邮件。因此,TelephonyManager.getVoiceMailNumber()TelephonyManager.getCompleteVoiceMailNumber(),取决于您所需的口味。

希望这可以帮助。


5
没有“ getCompleteVoiceMailNumber”函数,加上getVoiceMailNumber()返回的数字与电话的真实数字不同。
Android开发者

这是一个技巧,仅适用于世界上的几个移动运营商。但是从技术上讲可以解决。
TECHNIK

0

添加此依赖项: implementation 'com.google.android.gms:play-services-auth:18.0.0'

要获取电话号码列表,请使用以下命令:

val hintRequest = HintRequest.Builder()
    .setPhoneNumberIdentifierSupported(true)
    .build()

val intent = Credentials.getClient(context).getHintPickerIntent(hintRequest)

startIntentSenderForResult(
    intent.intentSender,
    PHONE_NUMBER_FETCH_REQUEST_CODE,
    null,
    0,
    0,
    0,
    null
)

点击播放服务对话框后:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent? { 
    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == PHONE_NUMBER_FETCH_REQUEST_CODE) {
        data?.getParcelableExtra<Credential>(Credential.EXTRA_KEY)?.id?.let { 
            useFetchedPhoneNumber(it)
        }
    }
}

-6

在开发一个安全应用程序时,我需要这样做,以便我的手机可能会碰到谁的电话号码。1.接收启动完成,然后尝试从telephonyManager获取Line1_Number,它返回字符串结果。2.将字符串结果与我自己的电话号码进行比较,如果不匹配或字符串返回null,则3.将包含字符串结果和特殊符号的SMS秘密发送到我的办公室号码。4.如果消息发送失败,请启动服务,并在每个小时后继续尝试,直到发送的SMS挂起意图返回成功为止。通过此步骤,我可以使用丢失的电话获得该人员的号码。收费是否无关紧要。


为什么要投票?
humble_wolf
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.