web-dev-qa-db-ja.com

SMSおよびMMSのAndroid(キットカット前Android 4.4)の送受信

SMSメッセージを送受信する方法を見つけました。 SMSメッセージを送信するには、SmsManagerクラスのsendTextMessage()およびsendMultipartTextMessage()メソッドを呼び出す必要がありました。 SMSメッセージを受信するには、AndroidMainfest.xmlファイルに受信者を登録する必要がありました。次に、BroadcastReceiveronReceive()メソッドをオーバーライドする必要がありました。以下に例を示しました。

MainActivity.Java

public class MainActivity extends Activity {
    private static String SENT = "SMS_SENT";
    private static String DELIVERED = "SMS_DELIVERED";
    private static int MAX_SMS_MESSAGE_LENGTH = 160;

    // ---sends an SMS message to another device---
    public static void sendSMS(String phoneNumber, String message) {

        PendingIntent piSent = PendingIntent.getBroadcast(mContext, 0, new Intent(SENT), 0);
        PendingIntent piDelivered = PendingIntent.getBroadcast(mContext, 0,new Intent(DELIVERED), 0);
        SmsManager smsManager = SmsManager.getDefault();

        int length = message.length();          
        if(length > MAX_SMS_MESSAGE_LENGTH) {
            ArrayList<String> messagelist = smsManager.divideMessage(message);          
            smsManager.sendMultipartTextMessage(phoneNumber, null, messagelist, null, null);
        }
        else
            smsManager.sendTextMessage(phoneNumber, null, message, piSent, piDelivered);
        }
    }

    //More methods of MainActivity ...
}

SMSReceiver.Java

public class SMSReceiver extends BroadcastReceiver {
    private final String DEBUG_TAG = getClass().getSimpleName().toString();
    private static final String ACTION_SMS_RECEIVED = "Android.provider.Telephony.SMS_RECEIVED";
    private Context mContext;
    private Intent mIntent;

    // Retrieve SMS
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        mIntent = intent;

        String action = intent.getAction();

        if(action.equals(ACTION_SMS_RECEIVED)){

            String address, str = "";
            int contactId = -1;

            SmsMessage[] msgs = getMessagesFromIntent(mIntent);
            if (msgs != null) {
                for (int i = 0; i < msgs.length; i++) {
                    address = msgs[i].getOriginatingAddress();
                    contactId = ContactsUtils.getContactId(mContext, address, "address");
                    str += msgs[i].getMessageBody().toString();
                    str += "\n";
                }
            }   

            if(contactId != -1){
                showNotification(contactId, str);
            }

            // ---send a broadcast intent to update the SMS received in the
            // activity---
            Intent broadcastIntent = new Intent();
            broadcastIntent.setAction("SMS_RECEIVED_ACTION");
            broadcastIntent.putExtra("sms", str);
            context.sendBroadcast(broadcastIntent);
        }

    }

    public static SmsMessage[] getMessagesFromIntent(Intent intent) {
        Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
        byte[][] pduObjs = new byte[messages.length][];

        for (int i = 0; i < messages.length; i++) {
            pduObjs[i] = (byte[]) messages[i];
        }
        byte[][] pdus = new byte[pduObjs.length][];
        int pduCount = pdus.length;
        SmsMessage[] msgs = new SmsMessage[pduCount];
        for (int i = 0; i < pduCount; i++) {
            pdus[i] = pduObjs[i];
            msgs[i] = SmsMessage.createFromPdu(pdus[i]);
        }
        return msgs;
    }

    /**
    * The notification is the icon and associated expanded entry in the status
    * bar.
    */
    protected void showNotification(int contactId, String message) {
        //Display notification...
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.myexample"
    Android:versionCode="1"
    Android:versionName="1.0" >

    <uses-sdk
        Android:minSdkVersion="16"
        Android:targetSdkVersion="17" />

    <uses-permission Android:name="Android.permission.READ_CONTACTS" />
    <uses-permission Android:name="Android.permission.READ_PHONE_STATE" />
    <uses-permission Android:name="Android.permission.SEND_SMS" />
    <uses-permission Android:name="Android.permission.RECEIVE_SMS" />
    <uses-permission Android:name="Android.permission.READ_SMS" />
    <uses-permission Android:name="Android.permission.WRITE_SMS" />
    <uses-permission Android:name="Android.permission.RECEIVE_MMS" />
    <uses-permission Android:name="Android.permission.WRITE" />
    <uses-permission Android:name="Android.permission.VIBRATE" />
    <uses-permission Android:name="Android.permission.INTERNET" />
    <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        Android:debuggable="true"
        Android:icon="@drawable/ic_launcher_icon"
        Android:label="@string/app_name" >

        <activity
            //Main activity...
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />

                <category Android:name="Android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            //Activity 2 ...
        </activity>
        //More acitivies ...

        // SMS Receiver
        <receiver Android:name="com.myexample.receivers.SMSReceiver" >
            <intent-filter>
                <action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>

    </application>
</manifest>

ただし、MMSメッセージを同様の方法で送受信できるかどうか疑問に思っていました。いくつかの調査を行った後、ブログで提供されている多くの例は、単にIntentをネイティブメッセージングアプリケーションに渡します。アプリケーションを終了せずにMMSを送信しようとしています。 MMSを送受信する標準的な方法はないようです。誰かがこれを機能させましたか?

また、SMS/MMS ContentProviderは公式Android SDKの一部ではないことを認識していますが、誰かがこれを実装できると考えていました。どんな助けも大歓迎です。

更新

MMSメッセージを受信するためにAndroidManifest.xmlファイルにBroadcastReceiverを追加しました

<receiver Android:name="com.sendit.receivers.MMSReceiver" >
    <intent-filter>
        <action Android:name="Android.provider.Telephony.WAP_Push_RECEIVED" />

        <data Android:mimeType="application/vnd.wap.mms-message" />
    </intent-filter>
</receiver>

MMSReceiverクラスでは、onReceive()メソッドはメッセージの送信元のphoneNumberのみを取得できます。メディア添付ファイル(画像/音声/ビデオ)へのファイルパスやMMS内のテキストなど、MMSから他の重要なものをどのように取得しますか?

MMSReceiver.Java

public class MMSReceiver extends BroadcastReceiver {
    private final String DEBUG_TAG = getClass().getSimpleName().toString();
    private static final String ACTION_MMS_RECEIVED = "Android.provider.Telephony.WAP_Push_RECEIVED";
    private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";

     // Retrieve MMS
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        String type = intent.getType();

        if(action.equals(ACTION_MMS_RECEIVED) && type.equals(MMS_DATA_TYPE)){

            Bundle bundle = intent.getExtras();

            Log.d(DEBUG_TAG, "bundle " + bundle);
            SmsMessage[] msgs = null;
            String str = "";
            int contactId = -1;
            String address;

            if (bundle != null) {

                byte[] buffer = bundle.getByteArray("data");
                Log.d(DEBUG_TAG, "buffer " + buffer);
                String incomingNumber = new String(buffer);
                int indx = incomingNumber.indexOf("/TYPE");
                if(indx>0 && (indx-15)>0){
                    int newIndx = indx - 15;
                    incomingNumber = incomingNumber.substring(newIndx, indx);
                    indx = incomingNumber.indexOf("+");
                    if(indx>0){
                        incomingNumber = incomingNumber.substring(indx);
                        Log.d(DEBUG_TAG, "Mobile Number: " + incomingNumber);
                    }
                }

                int transactionId = bundle.getInt("transactionId");
                Log.d(DEBUG_TAG, "transactionId " + transactionId);

                int pduType = bundle.getInt("pduType");
                Log.d(DEBUG_TAG, "pduType " + pduType);

                byte[] buffer2 = bundle.getByteArray("header");      
                String header = new String(buffer2);
                Log.d(DEBUG_TAG, "header " + header);

                if(contactId != -1){
                    showNotification(contactId, str);
                }

                // ---send a broadcast intent to update the MMS received in the
                // activity---
                Intent broadcastIntent = new Intent();
                broadcastIntent.setAction("MMS_RECEIVED_ACTION");
                broadcastIntent.putExtra("mms", str);
                context.sendBroadcast(broadcastIntent);

            }
        }

    }

    /**
    * The notification is the icon and associated expanded entry in the status
    * bar.
    */
    protected void showNotification(int contactId, String message) {
        //Display notification...
    }
}

Android.provider.Telephonyのドキュメント によると:

ブロードキャストアクション:新しいテキストベースのSMSメッセージがデバイスによって受信されました。インテントには次の追加の値があります。

pdus-メッセージを構成するPDUを含むObject[]byte[]

追加の値はgetMessagesFromIntent(Android.content.Intent)を使用して抽出できます。BroadcastReceiverでこのインテントの処理中にエラーが発生した場合、結果コードを適切に設定する必要があります。

 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
 public static final String SMS_RECEIVED_ACTION = "Android.provider.Telephony.SMS_RECEIVED";

ブロードキャストアクション:新しいデータベースSMSメッセージがデバイスによって受信されました。インテントには次の追加の値があります。

pdus-メッセージを構成するPDUを含むObject[]byte[]

余分な値は、getMessagesFromIntent(Android.content.Intent)を使用して抽出できます。 BroadcastReceiverでこのインテントの処理中にエラーが発生した場合、結果コードを適切に設定する必要があります。

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String DATA_SMS_RECEIVED_ACTION = "Android.intent.action.DATA_SMS_RECEIVED";

ブロードキャストアクション:新しいWAPプッシュメッセージがデバイスによって受信されました。インテントには次の追加の値があります。

transactionId (Integer)-WAPトランザクションID

pduType (Integer)-WAP PDUタイプ `

header (byte[])-メッセージのヘッダー

data (byte[])-メッセージのデータペイロード

contentTypeParameters (HashMap<String,String>)-コンテンツタイプに関連付けられたパラメーター(WSP Content-Typeヘッダーからデコード)

BroadcastReceiverでこのインテントの処理中にエラーが発生した場合、結果コードを適切に設定する必要があります。 contentTypeParametersの追加値は、名前でキー設定されたコンテンツパラメーターのマップです。割り当てられていない既知のパラメータが見つかった場合、マップのキーは「unassigned/0x ...」になります。「...」は割り当てられていないパラメータの16進値です。パラメーターにNo-Valueがある場合、マップの値はnullになります。

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WAP_Push_RECEIVED_ACTION = "Android.provider.Telephony.WAP_Push_RECEIVED";

アップデート#2

PendingIntentで受け取るためにBroadcastReceiverでエキストラを渡す方法を考えました: Android PendingIntentエキストラ、BroadcastReceiverで受信しない

ただし、余分はSMSReceiverではなく、SendBroadcastReceiverに渡されます。 SMSReceiverに追加を渡すにはどうすればよいですか?

アップデート#3

MMSの受信

そのため、さらに調査を行った結果、ContentObserverを登録する提案がいくつかありました。そうすることで、content://mms-sms/conversationsコンテンツプロバイダーに変更があることを検出できるため、着信MMSを検出できます。これが私が見つけた機能するための最も近い例です: Receiving MMS

ただし、タイプmainActivityの変数ServiceControllerがあります。 ServiceControllerクラスはどこに実装されていますか?登録済みのContentObserverの他の実装はありますか?

MMSの送信

MMSの送信に関しては、この例に遭遇しました: Send MMS

問題は、Android v4.2.2にあるNexus 4でこのコードを実行しようとしたことです。このエラーが表示されます。

Java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has Android.permission.WRITE_APN_SETTINGS.

CarriersクラスのgetMMSApns()メソッドでAPNHelper ContentProviderを照会すると、エラーがスローされます。

final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);

どうやらできません Android 4.2のAPNを読む

モバイルデータを使用して操作(MMSの送信など)を実行し、デバイスに存在するデフォルトのAPN設定を知らないすべてのアプリケーションの代替手段は何ですか?

アップデート#4

MMSの送信

私はこの例に従ってみました: Send MMS

@Samが彼の答えで示唆したように:

You have to add jsoup to the build path, the jar to the build path and import com.droidprism.*; To do that in Android, add the jars to the libs directory first, then configure the project build path to use the jars already in the libs directory, then on the build path config click order and export and check the boxes of the jars and move jsoup and droidprism jar to the top of the build order.

そのため、SecurityExceptionエラーが発生しなくなりました。 Android KitKatのNexus 5でテストしています。サンプルコードを実行した後、次の呼び出しの後に200応答コードが返されます。

MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);

ただし、MMSを送信しようとした人に確認しました。そして、彼らはMMSを受け取ったことはないと言った。

131
toobsco42

上記とまったく同じ問題(t-mobile USAのGalaxy Nexus)がありました。モバイルデータがオフになっているためです。

Jelly Beanでは、設定>データ使用量>モバイルデータ

MMS ORを受信する前にモバイルデータをオンにする必要があることに注意してください。モバイルデータをオフにしてMMSを受け取った場合、新しいメッセージの通知を受け取り、ダウンロードボタンが付いたメッセージを受け取ります。ただし、事前にモバイルデータがない場合、着信MMS添付ファイルは受信されません。メッセージを受信した後でオンにしても。

何らかの理由で、電話プロバイダーがMMSの送受信機能を有効にしている場合、Wifiを使用している場合でも、モバイルデータを有効にする必要があります。モバイルデータが有効な場合は、受信できますWifiがデバイスでインターネットとして表示されている場合でも、MMSを送信します。

モバイルデータを有効にしていない場合でも、モバイルデータをオンにしている場合でもメッセージが大量にハングアップし、デバイスの再起動が必要になる可能性があるため、これは非常に苦痛です。

15
Manan Sharma

公式のAPIサポートはありません。つまり、一般向けに文書化されておらず、ライブラリはいつでも変更される可能性があります。私はあなたがアプリケーションを離れたくないことを理解していますが、不思議な人のためにあなたが意図してそれをどのように行うかをここに示します。

public void sendData(int num){
    String fileString = "..."; //put the location of the file here
    Intent mmsIntent = new Intent(Intent.ACTION_SEND);
    mmsIntent.putExtra("sms_body", "text");
    mmsIntent.putExtra("address", num);
    mmsIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(fileString)));
    mmsIntent.setType("image/jpeg");
    startActivity(Intent.createChooser(mmsIntent, "Send"));

}

メッセージの配信を追跡するなどの方法を完全には理解していませんが、これによりメッセージが送信されるはずです。

SMSと同じ方法でmmsの受信を警告できます。受信機のインテントフィルターは次のようになります。

<intent-filter>
    <action Android:name="Android.provider.Telephony.WAP_Push_RECEIVED" />
    <data Android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
7
user1959417

Android 4.0 api 14以降のapn設定を書き込む許可なしにmmsを送信するには、 this library :Androidからmncおよびmccコードを取得して呼び出します。

Carrier c = Carrier.getCarrier(mcc, mnc);
if (c != null) {
    APN a = c.getAPN();
    if (a != null) {
        String mmsc = a.mmsc;
        String mmsproxy = a.proxy; //"" if none
        int mmsport = a.port; //0 if none
    }
}

これを使用するには、ビルドパスに Jsoup とdroid prism jarを追加し、com.droidprism。*をインポートします。

4
Sam Adamsh

Androidでmmsを送信するためのSDKサポートはないと思います。 こちらをご覧ください 少なくとも私はまだ見つけていません。しかし、男はそれを持っていると主張した。この投稿をご覧ください。

AndroidのマイアプリケーションからMMSを送信

3