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


131

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

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メッセージを受信するBroadcastReceiverためにAndroidManifest.xmlファイル にを追加しました

<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()メソッドはメッセージの送信元の電話番号のみを取得できます。メディア添付ファイル(画像/音声/ビデオ)へのファイルパスや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-アンObject[]byte[]メッセージを構成するPDUを含む秒。

追加の値はgetMessagesFromIntent(android.content.Intent) 、BroadcastReceiverがこのインテントの処理中にエラーを検出した場合に、結果コードを適切に設定することで抽出できます。

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

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

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

追加の値は、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 PUSHメッセージがデバイスによって受信されました。インテントには、次の追加の値があります。

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が受信するBroadcastReceiverAndroidのPendingIntentのエキストラは、BroadcastReceiverによって受信されません

しかし、余分はに渡されるSendBroadcastReceiverないSMSReceiverSMSReceiverにエクストラを渡すにはどうすればよいですか?

アップデート#3

MMSの受信

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

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

MMSの送信

MMSの送信に関しては、次の例に遭遇しました。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.

エラーは、クラスのメソッドでCarriersContentProviderをクエリした後にスローされます。getMMSApns()APNHelper

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の送信

私はこの例に従ってみました:MMSを送信します

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

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を決して受け取っていないと述べた。


これまでにこのチュートリアルを見たことがありますか?maximbogatov.wordpress.com/2011/08/13/mms-in-android
HaemEternal

3
はい、あります。マキシムの回答をまとめて試してみましたが、うまく機能しません。そこには廃止予定のように見えるandroid.provider.telephonyをインポートするクラスがたくさんあります。
toobsco42 2013

そしておそらく、サヒールの答え@読んだ後、あなたはまた、この試してみた:stackoverflow.com/questions/2972845/...を
HaemEternal

@Sahilの回答と非常によく似ていますが、その回答をどのようにまとめるかはわかりません。
toobsco42 2013

こんにちは@ toobsco42あなたはあなたが上記のすべてのクエリの解決策を見つけることができますか?
kamal_tech_view 2013

回答:


15

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

Jelly Beanの場合:設定>データ使用量>モバイルデータ

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

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

それはあなたがそれを持っていないかのように、モバイルデータをオンにしても、メッセージがたくさんハングすることがあり、デバイスの再起動が必要になるかもしれないので、それは本当に痛いです。


また、SMSとMMSの送信は、バックグラウンドで2つのまったく異なるものであることも知っておく必要があります。MMSは、テキスト付きの追加アイテム(メディア)を送信する必要があるため、インターネットベースのネットワークサービスです。与えられたコードは、私がテストしたいくつかのデバイスで正常に動作します。PS:NOKIAの部分は無視できます。
Manan Sharma

この例を実行すると、LogCatに次のように出力されます:02-24 13:32:40.872:V / SendMMSActivity(5686):TYPE_MOBILE_MMS not connected、bail 02-24 13:32:40.882:V / SendMMSActivity(5686):type is TYPE_MOBILE_MMSではない、保釈また、java.lang.SecurityException:APN設定を書き込む権限がない:ユーザー10099も現在のプロセスもandroid.permission.WRITE_APN_SETTINGSを持っていません。このクエリは実行できないようです:final Cursor apnCursor = this.context.getContentResolver()。query(Uri.withAppendedPath(Carriers.CONTENT_URI、 "current")、null、null、null、null); Nexus 4での
IM

また、これは@Sahilが提供したものと同じ例です。
toobsco42 2013

7

公式の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>

これはネイティブのメッセージングアプリを起動するだけではありませんか?
toobsco42 2013年

1
うん、ごめんなさい。あなたはすでにその方法を知っていることに気づきました。mmsを受け取る方法を追加しました。
user1959417 2013年

ありがとう、私は最近MMSの一部を実装BroadcastReceiverしていてIntent Filter、あなたが投稿したものを使用しました。この質問はすぐに更新します。
toobsco42 2013年

4

APN設定を書き込む許可なしにAndroid 4.0 API 14以降のmmsを送信するには、次のライブラリを使用できます。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とドロイドプリズムjarをビルドパスに追加し、com.droidprism。*をインポートします。


@Samさん、プロジェクトに.jarファイルを追加しましたが、Carrierオブジェクトをインスタンス化する行でこのエラーが発生しています。それ java.lang.NoClassDefFoundError: com.droidprism.Carrier はあなたに起こっていますか?
toobsco42 2013

番号。jsoupをビルドパスに追加し、jarをビルドパスに追加して、com.droidprism。*をインポートする必要があります。答えを編集します。Androidでこれを行うには、まずjarをlibsディレクトリに追加し、プロジェクトのビルドパスを構成して、libsディレクトリにすでにあるjarを使用します。次に、ビルドパスの構成で、注文をクリックしてエクスポートし、jarのボックスをチェックして移動します。 jsoupとdroidprismのjarをビルド順序の一番上に配置します。
サムアダムシュ2013

Jsoup .jarを追加すると、NoClassDefFoundErrorが解決されました。APN設定を取得できるようになりました。次のステップは、MMSの送信方法を理解することです。
toobsco42 2013

3

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

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


私はNokia実装のandroidbridge.blogspot.com投稿のコメントを見て、多くの人がデバイスでこれを機能させるのに問題を抱えているようです。
toobsco42 2013年

@ toobsco42したがって、まだサポートされていない可能性があります。
Sahil Mahajan Mj 2013

-2

私は欲求不満を理解していません。このインテントをフィルタリングするbroadcastreceiverを作成しないのはなぜですか。

android.provider.Telephony.MMS_RECEIVED

私はもう少しチェックしました、そしてこれを得るためにあなたはシステムレベルのアクセスを必要とするかもしれません(根ざした電話)。


3
@ j2emanue様、問題はこのインテントを受け取った後、どのように実際にMMSのコンテンツを取得するのですか?MMSに画像とテキストが含まれている場合、これらのコンポーネントをどのように抽出しますか。
toobsco42 14

しかし、私が言及した方法でそれを行うと、追加でバイト配列を取得できることに気づきました.... byte [] data = intent.getByteArrayExtra( "data"); 申し訳ありませんが、解析方法がわかりません。
j2emanue 2014

解析できます。しかし、私が得ることができるのは、件名、mmsの出身地、およびmmsのコンテンツが格納されているcontentlocationだけです。ただし、このURLにはアクセスできません。
toobsco42 14

-2

SmsListenerClass

public class SmsListener extends BroadcastReceiver {

static final String ACTION =
        "android.provider.Telephony.SMS_RECEIVED";

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

    Log.e("RECEIVED", ":-:-" + "SMS_ARRIVED");

    // TODO Auto-generated method stub
    if (intent.getAction().equals(ACTION)) {

        Log.e("RECEIVED", ":-" + "SMS_ARRIVED");

        StringBuilder buf = new StringBuilder();
        Bundle bundle = intent.getExtras();
        if (bundle != null) {

            Object[] pdus = (Object[]) bundle.get("pdus");

            SmsMessage[] messages = new SmsMessage[pdus.length];
            SmsMessage message = null;

            for (int i = 0; i < messages.length; i++) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    String format = bundle.getString("format");
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
                } else {
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                }

                message = messages[i];
                buf.append("Received SMS from  ");
                buf.append(message.getDisplayOriginatingAddress());
                buf.append(" - ");
                buf.append(message.getDisplayMessageBody());
            }

            MainActivity inst = MainActivity.instance();
            inst.updateList(message.getDisplayOriginatingAddress(),message.getDisplayMessageBody());

        }

        Log.e("RECEIVED:", ":" + buf.toString());

        Toast.makeText(context, "RECEIVED SMS FROM :" + buf.toString(), Toast.LENGTH_LONG).show();

    }
}

アクティビティ

@Override
public void onStart() {
    super.onStart();
    inst = this;
}

public static MainActivity instance() {
    return inst;
}

public void updateList(final String msg_from, String msg_body) {

    tvMessage.setText(msg_from + " :- " + msg_body);

    sendSMSMessage(msg_from, msg_body);

}

protected void sendSMSMessage(String phoneNo, String message) {

    try {
        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendTextMessage(phoneNo, null, message, null, null);
        Toast.makeText(getApplicationContext(), "SMS sent.", Toast.LENGTH_LONG).show();
    } catch (Exception e) {
        Toast.makeText(getApplicationContext(), "SMS faild, please try again.", Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }
}

マニフェスト

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

<receiver android:name=".SmsListener">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.