I am trying to verify the phone number of an Android device by having the device send an SMS to itself, and automatically checking if the SMS has been received. How can I do this?
相关问题
- How can I create this custom Bottom Navigation on
- Bottom Navigation View gets Shrink Down
- How to make that the snackbar action button be sho
- Listening to outgoing sms not working android
- How to create Circular view on android wear?
相关文章
- android开发 怎么把图片放入drawable的文件夹下
- android上如何获取/storage/emulated/下的文件列表
- androidStudio有个箭头不认识
- SQLite不能创建表
- Windows - Android SDK manager not listing any plat
- Animate Recycler View grid when number of columns
- Why is the app closing suddenly without showing an
- Android OverlayItem.setMarker(): Change the marker
To begin, this will require two permissions; one to send SMS messages, and one to receive them. The following needs to be in your AndroidManifest.xml, between the
<manifest>
tags, but outside of the<application>
tags.These are both dangerous permissions, so you will need to handle them accordingly if your app is to run on Marshmallow (API level 23) or above, and has a
targetSdkVersion
of 23+. Information on how to request these permissions at runtime can be found on this developer page.The Java classes you will need are in the
android.telephony
package; specificallyandroid.telephony.SmsManager
andandroid.telephony.SmsMessage
. Do make certain you've got the correct classes imported for both.To send the outgoing SMS, you will use
SmsManager
'ssendTextMessage()
method, which has the following signature:Only two arguments are required in this method call -
destinationAddress
andtext
; the first being the phone number, the second being the message content.null
can be passed for the rest. For example:It's important to keep the message text relatively short, as
sendTextMessage()
will usually fail silently if the text length exceeds the character limit for a single message.To receive and read the incoming message, you will need to register a
BroadcastReceiver
with anIntentFilter
for the"android.provider.Telephony.SMS_RECEIVED"
action. This Receiver can be registered either statically in the manifest, or dynamically on aContext
at runtime.Statically registering the Receiver class in the manifest will allow your app to receive the incoming message even if your app should happen to be killed before receipt. It may, however, take a little extra work to get the results where you want them. Between the
<application>
tags:The
PackageManager#setComponentEnabledSetting()
method can be used to enable and disable this<receiver>
as needed.Dynamically registering a Receiver instance on a
Context
can be a little easier to manage, code-wise, as the Receiver class could be made an inner class on whichever component registers it, and therefore have direct access to that component's members. However, this approach might not be as reliable as static registration, as a few different things could prevent the Receiver from getting the broadcast; e.g., your app's process being killed, the user navigating away from the registeringActivity
, etc.Do remember to unregister the Receiver when appropriate.
In the Receiver's
onReceive()
method, the actual message comes as an array ofbyte
arrays attached to theIntent
as an extra. The decoding details vary depending on the Android version, but the result here is a singleSmsMessage
object that will have the phone number and message you're after.At this point, you simply compare the
number
here to the one passed to thesendTextMessage()
call. It's advisable to usePhoneNumberUtils.compare()
for this, since the number retrieved in the Receiver might be in a different format than the one addressed.Notes:
The example demonstrated here is using one single-part message, thus why the message text should be restricted to a relatively short length. If you do want to send a longer message, for some reason, the
sendMultipartTextMessage()
method can be used instead. You would need to split up the text first, usingSmsManager#divideMessage()
, and passing the resultingArrayList
to that method, in lieu of the messageString
. To reassemble the complete message in the Receiver, you'd have to decode eachbyte[]
into anSmsMessage
, and concatenate the message bodies.Since KitKat (API level 19), if your app is not the default messaging app, the messages used here are going to be saved to the SMS Provider by the system and default app, and will therefore be available to any other app that uses the Provider. There's not much you can do about that, but if you really want to avoid it, this same technique can be used with data SMS, which do not trigger the default app, and won't be saved to the Provider.
For this, the
sendDataMessage()
method is used, which will need an additionalshort
argument for the (arbitrary) port number, and the message is passed as abyte[]
, rather than aString
. The action to filter for is"android.intent.action.DATA_SMS_RECEIVED"
, and the filter will need a data scheme and authority (host and port) set. In the manifest, it would look like:and there are corresponding methods in the
IntentFilter
class to set those dynamically.Decoding the
SmsMessage
is the same, but the messagebyte[]
is retrieved withgetUserData()
, rather thangetMessageBody()
.Prior to KitKat, apps were responsible for writing their own outgoing messages, so you can just not do that on those versions, if you don't want any record of it.
Incoming messages could be intercepted, and their broadcasts aborted before the main messaging app could receive and write them. To accomplish this, the filter's priority is set to the maximum, and
abortBroadcast()
is called in the Receiver. In the static option, theandroid:priority="999"
attribute is added to the opening<intent-filter>
tag. Dynamically, theIntentFilter#setPriority()
method can do the same.This is not at all reliable, as it is always possible for another app to have a higher precedence than yours.
I've omitted securing the Receiver with the broadcaster's permission in these examples, partly for simplicity and clarity, and partly because the nature of the thing wouldn't really leave you open to any sort of spoofing that could do harm. However, if you'd like to include this, then you merely need to add the
android:permission="android.permission.BROADCAST_SMS"
attribute to the opening<receiver>
tag for the static option. For the dynamic, use the four-parameter overload of theregisterReceiver()
method, passing that permissionString
as the third argument, andnull
as the fourth.