2013-11-21 51 views

回答

57

首先,这需要两个权限;一个发送短信,一个发送短信。以下内容需要在您的AndroidManifest.xml中,<manifest>标签之间,但在<application>标签之外。

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

这些都是非常危险的权限,所以你需要相应地处理他们,如果你的应用程序是在棉花糖(API等级23)或以上运行,并具有23+一targetSdkVersion。有关如何在运行时请求这些权限的信息可在this developer page上找到。


您将需要的Java类位于android.telephony包中;具体为android.telephony.SmsManagerandroid.telephony.SmsMessage。确保你有两个正确的导入类。

要发送的短信外发,你将使用的SmsManagersendTextMessage()方法,它具有以下特征:

sendTextMessage(String destinationAddress, String scAddress, String text, 
       PendingIntent sentIntent, PendingIntent deliveryIntent) 

只有两个论据都需要在这个方法的调用 - destinationAddresstext;第一个是电话号码,第二个是消息内容。其余的可以通过null。例如:

String number = "1234567890"; 
String message = "Verification message."; 
SmsManager sm = SmsManager.getDefault(); 
sm.sendTextMessage(number, null, message, null, null); 

保持消息文本比较短是很重要的,因为如果sendTextMessage()文本长度超过单条信息的字符数限制通常会静默失败。


接收和阅读收到的消息,您将需要注册与IntentFilter一个BroadcastReceiver"android.provider.Telephony.SMS_RECEIVED"行动。该Receiver可以静态注册在清单中,或者在运行时动态地注册到Context

  • 静态登记清单中的接收器类将让您的应用程序接收传入的消息,即使您的应用程序应该发生收货前被杀害。然而,它可能需要一些额外的工作来获得你想要的结果。所述<application>标签之间:

    <receiver 
        android:name=".SmsReceiver" 
        android:enabled="false"> 
        <intent-filter> 
         <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
        </intent-filter> 
    </receiver> 
    

    PackageManager#setComponentEnabledSetting()方法可用于启用和根据需要禁用此<receiver>

  • 动态注册上的Context一个接收器的实例可以是一个小更容易管理,代码明智的,作为接收器类可以作出关于哪个部件注册它的内部类,所以具有该组件的部件的直接访问。但是,这种方法可能不如静态注册那样可靠,因为一些不同的事情可能会阻止接收器获得广播;例如,您的应用程序的进程被终止,用户远离注册Activity

    SmsReceiver receiver = new SmsReceiver(); 
    IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); 
    registerReceiver(receiver, filter); 
    

    是否记得在适当的时候注销Receiver。


在接收机的onReceive()方法,实际的消息来作为附着到Intent作为额外byte数组的数组。解码细节因安卓版本而异,但这里的结果是一个单一的SmsMessage对象,它会包含您之后的电话号码和消息。

class SmsReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     SmsMessage msg; 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 
      SmsMessage[] msgs = Telephony.Sms.Intents.getMessagesFromIntent(intent); 
      msg = msgs[0]; 
     } else { 
      Object pdus[] = (Object[]) intent.getExtras().get("pdus"); 
      msg = SmsMessage.createFromPdu((byte[]) pdus[0]); 
     } 

     String number = msg.getOriginatingAddress(); 
     String message = msg.getMessageBody(); 
     ... 
    } 
} 

在这一点上,你只需在这里比较number到一个传递给sendTextMessage()通话。为此,建议使用PhoneNumberUtils.compare(),因为在Receiver中检索到的数字可能与所处理的格式不同。


注:

  • 示例这里展示使用一个单一的部分消息,从而为什么消息文本应只限于相对短的长度。如果您确实想发送更长的消息,出于某种原因,可以使用sendMultipartTextMessage()方法代替。您需要首先分割文本,使用SmsManager#divideMessage(),并将生成的ArrayList传递给该方法,以代替消息String。要在Receiver中重新组合完整的消息,您必须将每个byte[]解码为SmsMessage,然后连接消息体。

  • 由于KitKat(API级别19),如果您的应用程序不是默认的消息应用程序,此处使用的消息将由系统和默认应用程序保存到SMS提供程序,因此可用于任何其他使用提供者的应用程序。关于这一点你可以做的事情不多,但如果你真的想避免它,这种技术可以用于数据短信,它不会触发默认的应用程序,也不会保存到提供商。

    为此,sendDataMessage()方法被使用,这将需要一个额外的参数short为(任意的)的端口号,并且该消息被作为一个byte[]通过,而不是一个String。要过滤的操作是"android.intent.action.DATA_SMS_RECEIVED",过滤器需要数据方案和权限(主机和端口)集。在清单中,它看起来像:

    <intent-filter> 
        <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> 
        <data 
         android:scheme="sms" 
         android:host="localhost" 
         android:port="1234" /> 
    </intent-filter> 
    

    ,并有在IntentFilter类对应的方法来设置这些动态。

    解码SmsMessage是相同的,但消息byte[]检索与getUserData(),而不是getMessageBody()

  • 在使用KitKat之前,应用程序负责编写自己的传出消息,因此如果您不需要任何记录,那么您可以在这些版本上不这样做。

    传入的消息可能被拦截,并且它们的广播在主消息传递应用程序可以接收和写入它们之前中止。为了实现这一点,过滤器的优先级设置为最大值,并在接收器中调用abortBroadcast()。在静态选项中,android:priority="999"属性被添加到开头的<intent-filter>标记中。动态地,IntentFilter#setPriority()方法可以做同样的事情。

    这并非完全可靠,因为其他应用程序始终有可能比您拥有更高的优先级。

  • 在这些例子中,我省略了Receiver的广播者许可,部分原因是为了简单明了,部分原因是因为事物的性质不会让你接触到任何可能造成伤害的欺骗。但是,如果您想要包含此选项,则只需将android:permission="android.permission.BROADCAST_SMS"属性添加到静态选项的开头<receiver>标记中即可。对于动态,请使用registerReceiver()方法的四参数超载,将权限String作为第三个参数,将null作为第四个参数。

+7

非常感谢您的详细,完整的响应。 –

3

Sinch SDK允许您使用Flash呼叫技术验证用户的电话号码。它依靠普通电话网络,所以如果用户电话号码有效,您会收到未接电话。

private void startVerification(String phoneNumber) { 
Config config = SinchVerification.config().applicationKey("your_app_key").context(getApplicationContext()).build(); 
VerificationListener listener = new MyVerificationListener(); 
verification = SinchVerification.createFlashCallVerification(config, phoneNumber, listener); 
verification.initiate(); 
} 

欲了解更多信息,你可以看看这个教程:

https://www.sinch.com/tutorials/android-flash-call-verification/

+0

不要只是重新发布什么版主删除没有解决评论。你可以在你的文章中加入[affiliation disclosure](https://stackoverflow.com/help/promotion)吗?否则,这篇文章也将被删除为垃圾邮件。 –