使用本机SMS API在Android应用程序内部发送和接收短信,而不是在本机消息应用程序中发送。

9

我在我的应用程序中有一个需求,需要集成应用内消息功能。我想使用Android原生的短信API来发送和接收消息。主要的挑战是我不想在消息应用程序中显示接收到的消息。所有的消息都应该只从我的应用程序中打开和发送。

我尝试通过广播接收器接收以下意图:

<intent-filter>
    <action android:name="android.provider.telephony.SMS_RECEIVED"></action>
</intent-filter>

但是当信息同时到达我的应用程序时,原生消息应用程序也会收到信息,这不是我想要的。

我还尝试在模拟器上发送数据消息到特定端口,发送消息成功,但是我的应用程序以及其他模拟器上的原生消息应用程序都没有接收到。

意图过滤器是:

<intent-filter> 
        <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
        <data android:port="8901"/>
        <data android:scheme="sms"/>
</intent-filter>

我正在使用给定端口的sendDataMessage()函数。

是否有更好、更安全的方式发送消息,以确保在使用安卓本机SMS API时没有可能窃取您的数据?如果没有,我可以选择什么替代方案来实现相同的功能。


@Tom 谢谢你的建议。我已经编辑了问题并附上了我的努力。请打开问题,这样我就可以得到答案。对我来说非常紧急。 - Piyush Agarwal
我也需要这个。你找到了解决方案或替代方法吗?如果是,请将其作为您自己的答案发布。谢谢。 - Qadir Hussain
2
@QadirHussain,是的,我已经找到解决方案并实现了。我会在今天发布它。在KitKat中,这现在变得更加容易了。 - Piyush Agarwal
再次感谢。请尽快复制粘贴,我非常急需这个。 - Qadir Hussain
@QadirHussain,我已经发布了我的答案。 - Piyush Agarwal
3个回答

10

这是我已经实现的内容,它完全按照我的要求运作。

在输入电话号码和文本消息后,调用此方法。

private static final int MAX_SMS_MESSAGE_LENGTH = 160;
private static final int SMS_PORT = 8901;
private static final String SMS_DELIVERED = "SMS_DELIVERED";
private static final String SMS_SENT = "SMS_SENT";

private void sendSms(String phonenumber,String message) { 

    SmsManager manager = SmsManager.getDefault();
    PendingIntent piSend = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SENT), 0);
    PendingIntent piDelivered = PendingIntent.getBroadcast(this, 0, new Intent(SMS_DELIVERED), 0);

byte[] data = new byte[message.length()];

for(int index=0; index<message.length() && index < MAX_SMS_MESSAGE_LENGTH; ++index)
    {
       data[index] = (byte)message.charAt(index);
    }

manager.sendDataMessage(phonenumber, null, (short) SMS_PORT, data,piSend, piDelivered);

}



 private BroadcastReceiver sendreceiver = new BroadcastReceiver()
 {
         @Override
         public void onReceive(Context context, Intent intent)
         {
                 String info = "Send information: ";

                 switch(getResultCode())
                 {
                         case Activity.RESULT_OK: info += "send successful"; break;
                         case SmsManager.RESULT_ERROR_GENERIC_FAILURE: info += "send failed, generic failure"; break;
                         case SmsManager.RESULT_ERROR_NO_SERVICE: info += "send failed, no service"; break;
                         case SmsManager.RESULT_ERROR_NULL_PDU: info += "send failed, null pdu"; break;
                         case SmsManager.RESULT_ERROR_RADIO_OFF: info += "send failed, radio is off"; break;
                 }

                 Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();

         }
 };

 private BroadcastReceiver deliveredreceiver = new BroadcastReceiver()
 {
         @Override
         public void onReceive(Context context, Intent intent)
         {
                 String info = "Delivery information: ";

                 switch(getResultCode())
                 {
                         case Activity.RESULT_OK: info += "delivered"; break;
                         case Activity.RESULT_CANCELED: info += "not delivered"; break;
                 }

                 Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
         }
 };

您用于接收消息的接收器应该长这样:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

public class MySMSReceiver extends BroadcastReceiver {

String action,from,message;

@Override
public void onReceive(Context context, Intent intent) {


     action=intent.getAction();

    Bundle bundle = intent.getExtras();        
    SmsMessage[] msgs = null;


        if(null != bundle)
        {
            String info = "Binary SMS from ";
            Object[] pdus = (Object[]) bundle.get("pdus");
            msgs = new SmsMessage[pdus.length];

            byte[] data = null;

            for (int i=0; i<msgs.length; i++){
                msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);                
                info += msgs[i].getOriginatingAddress();                    
                info += "\n*****BINARY MESSAGE*****\n";
                from= msgs[i].getOriginatingAddress(); 
                data = msgs[i].getUserData();

                for(int index=0; index<data.length; ++index) {
                   info += Character.toString((char)data[index]);
                   message += Character.toString((char)data[index]);
                }
            }

        }

    Intent showMessage=new Intent(context, AlertMessage.class);
    showMessage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    showMessage.putExtra("from", from);
    showMessage.putExtra("message", message);
    context.startActivity(showMessage);

}

}

我创建了一个简单的活动AlertMessage.java来显示接收到的消息。

我在清单文件中注册广播接收器的方式:

 <receiver android:name=".MySMSReceiver">
     <intent-filter>
        <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> 
        <data android:scheme="sms" /> 
        <data android:port="8901" />      
     </intent-filter> 
 </receiver>

此处提到的端口必须与我们在sendSMS()方法中指定的端口相同,以便发送消息。

更新:

正在运行项目的Github存储库

https://github.com/pyus-13/MySMSSender


尝试使用不同的端口号。 - Piyush Agarwal
仍然不起作用。您在AlertMessage类中使用哪些代码来接收消息? - Nii Laryea
AlertMessage 不负责接收消息,它只是一个带有两个 TextView 的 Activity,没有其他功能。请稍等片刻,让我将其添加到我的 Github 存储库中。 - Piyush Agarwal
好的,请完成后在这里提供链接。 - Nii Laryea
如果我勾选了发送二进制短信复选框并发送消息,那么发送将成功,并且消息也会被传递(根据显示的 Toast)。但是,然后在 MySMSReceiver 类中要记录的消息没有被记录下来,这意味着应用程序从未接收到该消息。但是你说它在你的设备上可以工作,我不知道为什么它在我的设备上无法工作! - Nii Laryea
显示剩余6条评论

3
根据我的理解,这是可能的。您可以将您的应用程序设置为更高的优先级,例如:

<intent-filter android:priority="100"> 

在您的manifest.xml文件中注册广播接收器。这样所有消息都将首先通过您的应用程序,您可以将这些消息存储在数据库中。同时,如果您要中止广播,请使用


abortbroadcast();

您将不会收到任何通知,无论在哪里。

我听说过一些端口到端口的数据消息传递,这能有所帮助吗?如果另一个应用程序设置了比我的优先级更高的优先级,那该怎么办? - Piyush Agarwal
抱歉,我对端口到端口的数据消息传递概念不太熟悉。至于第二个问题,在我的有限知识范围内,我找到的唯一方法是给你的应用程序赋予更高的优先级。也许还有其他解决方案,但这是我知道的一种方式。希望这能帮助到你,亲爱的朋友 :) - thampi joseph

2

无论如何,你的应用程序都不能更改其他应用程序的权限,因此无法阻止默认的消息应用程序接收短信消息。


有什么替代方法可以实现相同的目标? - Piyush Agarwal
@pyus13 在非root设备上没有其他替代方法。唯一的方法是忽略默认短信应用程序正在接收短信消息的事实。如果用户无论如何都想使用您的应用程序而不是默认的应用程序,那么您为什么还要费心呢? - Piotr Chojnacki
我的客户由于一些安全问题不想这样做。是否有第三方API可以为客户端和服务器端组件提供相同类型的功能,以使用像XMPP这样的互联网服务设置消息协议? - Piyush Agarwal
@pyus13 我从未听说过这样的事情。我建议先考虑这个“安全”问题,然后尝试找出它是否真的是一个问题。 - Piotr Chojnacki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接