Java Android-以编程方式发送彩信,而不是默认应用程序
安卓SDK的MMS部分基本上没有公开,因此确实有一些方法可以帮助解决这个问题。但是,库中包含的示例项目不会发送彩信 下载后一个项目时,我可以运行示例并发送彩信,而无需将应用程序设置为默认应用程序。但是,当我将代码集成到自己的应用程序中时,只有当我将自己的应用程序设置为默认的消息应用程序时,彩信才会发送。我读到安卓4.4+不支持彩信,但它不是默认的应用程序,但为什么我从中提取代码的示例项目不支持默认应用程序?我真正注意到的唯一区别是,最小SDK是14,而我的项目是18 以下是我的项目的主要代码: Manifest.xmlJava Android-以编程方式发送彩信,而不是默认应用程序,java,android,sms,mms,Java,Android,Sms,Mms,安卓SDK的MMS部分基本上没有公开,因此确实有一些方法可以帮助解决这个问题。但是,库中包含的示例项目不会发送彩信 下载后一个项目时,我可以运行示例并发送彩信,而无需将应用程序设置为默认应用程序。但是,当我将代码集成到自己的应用程序中时,只有当我将自己的应用程序设置为默认的消息应用程序时,彩信才会发送。我读到安卓4.4+不支持彩信,但它不是默认的应用程序,但为什么我从中提取代码的示例项目不支持默认应用程序?我真正注意到的唯一区别是,最小SDK是14,而我的项目是18 以下是我的项目的主要代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hacknow2">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:name=".init.App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".phase1.PermissionsActivity"/>
<activity android:name=".phase2.youtube.YoutubeActivity" />
<activity android:name=".phase2.posting.PostingActivity" />
<activity
android:name=".phase2.ui.main.SelectionActivity"
android:label="@string/title_activity_selection"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</activity>
<activity android:name=".phase1.OpeningActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".phase3.mms.KitSmsSentReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<receiver
android:name=".phase3.mms.KitMmsSentReceiver"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<receiver
android:name="com.klinker.android.send_message.MmsSentReceiver"
android:taskAffinity="com.klinker.android.messaging.MMS_SENT" />
<receiver
android:name="com.klinker.android.send_message.MmsReceivedReceiver"
android:taskAffinity="com.klinker.android.messaging.MMS_RECEIVED" />
<service android:name="com.android.mms.transaction.TransactionService" />
<service
android:name=".phase3.mms.HeadlessSmsSendService"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
</application>
</manifest>
彩信管理器,管理发送彩信的单件
public class MMSManager {
private static final String TAG = "MMSManager";
private static ThreadPoolExecutor mThreadManager;
private static MMSManager INSTANCE;
private static BlockingQueue<Runnable> decodeWorkQueue;
private static int NUMBER_OF_CORES =
Runtime.getRuntime().availableProcessors();
private Settings mSettings;
private Context mContext;
private MMSManager(Context c) {
mContext = c;
initSettings();
initLogging();
// A queue of Runnables
decodeWorkQueue = new LinkedBlockingQueue<Runnable>();
// setting the thread factory
mThreadManager = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES,
50, TimeUnit.MILLISECONDS, decodeWorkQueue);
BroadcastUtils.sendExplicitBroadcast(c, new Intent(), "test action");
}
//See https://stackoverflow.com/questions/14057273/android-singleton-with-global-context
private static synchronized MMSManager getSync() {
if (INSTANCE == null) INSTANCE = new MMSManager(App.get());
return INSTANCE;
}
public static MMSManager getInstance(Context c) {
if (INSTANCE == null) {
INSTANCE = getSync();
}
return INSTANCE;
}
private void initSettings() {
mSettings = Settings.get(mContext);
if (TextUtils.isEmpty(mSettings.getMmsc()) &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
initApns();
}
}
private void initApns() {
ApnUtils.initDefaultApns(mContext, new ApnUtils.OnApnFinishedListener() {
@Override
public void onFinished() {
mSettings = Settings.get(mContext, true);
}
});
}
private void initLogging() {
com.klinker.android.logger.Log.setDebug(true);
com.klinker.android.logger.Log.setPath("messenger_log.txt");
com.klinker.android.logger.Log.setLogListener(new OnLogListener() {
@Override
public void onLogged(String tag, String message) {
//logAdapter.addItem(tag + ": " + message);
android.util.Log.d("MMS_Manager " + tag, "onLogged: " + message);
}
});
}
//Not sure what exception might pop up but it's being handled anyway...
public void sendMMS(String phoneNumber, Bitmap bm) {
mThreadManager.execute(new Runnable() {
@Override
public void run() {
Log.d("ThreadPool/MMSManager", "Trying to send MMS.");
com.klinker.android.send_message.Settings sendSettings = new com.klinker.android.send_message.Settings();
sendSettings.setMmsc(mSettings.getMmsc());
sendSettings.setProxy(mSettings.getMmsProxy());
sendSettings.setPort(mSettings.getMmsPort());
sendSettings.setUseSystemSending(true);
Transaction transaction = new Transaction(mContext, sendSettings);
Message message = new Message(null, phoneNumber);
if (bm != null)
message.setImage(bm);
transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
}
});
}
}
公共类管理器{
私有静态最终字符串TAG=“MMSManager”;
私有静态线程池执行器mThreadManager;
私有静态MMSManager实例;
私有静态阻塞队列;
内核的私有静态整数=
Runtime.getRuntime().availableProcessors();
私人设置mSettings;
私有上下文;
专用彩信管理器(上下文c){
mContext=c;
初始化设置();
initLogging();
//一队跑龙套的人
decodeWorkQueue=新建LinkedBlockingQueue();
//设置螺纹工厂
mThreadManager=新的ThreadPoolExecutor(内核的数量、内核的数量、,
50,TimeUnit.ms,decodeWorkQueue);
sendplicitbroadcast(c,newintent(),“测试操作”);
}
//看https://stackoverflow.com/questions/14057273/android-singleton-with-global-context
专用静态同步彩信管理器getSync(){
如果(INSTANCE==null)INSTANCE=newmmsmanager(App.get());
返回实例;
}
公共静态MMSManager getInstance(上下文c){
if(实例==null){
INSTANCE=getSync();
}
返回实例;
}
私有void initSettings(){
mSettings=Settings.get(mContext);
if(TextUtils.isEmpty(mSettings.getMmsc())&&
Build.VERSION.SDK_INT
调用MMSManager方法的片段,位于其父级SelectionActivity中:
public class SendDialog extends DialogFragment {
private static final int MY_PERMISSIONS_REQUEST_SEND_SMS = 1000;
private ArrayList<String> mPhoneNumbers;
private DMessage mMessage;
private OnFinished mCompletionListener;
private MMSManager mMMSManager;
private Bitmap mBitmap;
private static String[] mMediaTypes;
public SendDialog(ArrayList<String> phoneNumbers, DMessage m, OnFinished listener){
mPhoneNumbers = phoneNumbers;
mMessage = m;
mCompletionListener = listener;
}
public SendDialog(ArrayList<String> phoneNumbers, DMessage m, Bitmap b, OnFinished listener){
mPhoneNumbers = phoneNumbers;
mMessage = m;
mCompletionListener = listener;
mBitmap = b;
}
public interface OnFinished{
void complete(boolean success);
}
private String getCautionMessage(){
int numContacts = 0;
if(mPhoneNumbers!=null && mPhoneNumbers.size()>0) {
for (String number :
mPhoneNumbers) {
numContacts++;
}
}
return "Are you sure you'd like to send the highlighted post to " + numContacts + " people?";
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mMediaTypes = getResources().getStringArray(R.array.postoptions);
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getCautionMessage())
.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
sendBulkTexts();
dismiss();
}
})
.setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mCompletionListener.complete(false);
}
});
// Create the AlertDialog object and return it
return builder.create();
}
private boolean isMMS(){
return mMessage.getMediaType().equals(mMediaTypes[2]);//mediaTypes[2] == "Image"
}
/**
* Converts phone number to only numbers.
* I.e. (XXX)-XXX-XXXX to XXXXXXXXXX
*/
private static String phoneNumberFormatter(String unformatted) {
return unformatted.replaceAll("\\D+", "");
}
private void sendBulkTexts(){
for (String number :
mPhoneNumbers) {
try {
String formattedNumber = phoneNumberFormatter(number);
if(!isMMS()) {
//Send a Youtube video or text
sendSMS(formattedNumber, mMessage.getBody());
}
else{
if(mMMSManager==null)//instantiate MMSManager and load bitmap
mMMSManager = MMSManager.getInstance(getActivity());
if(mBitmap!=null)
mMMSManager.sendMMS(formattedNumber, mBitmap);
}
}
catch(Exception e){
Toast.makeText(getActivity(), "Could not send text to " + number + ".", Toast.LENGTH_LONG).show();
Log.e("SendDialog", "sendBulkTexts: ", e);
mCompletionListener.complete(false);
}
}
Toast.makeText(getActivity(), "Finished sending texts.", Toast.LENGTH_LONG).show();
mCompletionListener.complete(true);
}
private void sendSMS(String phoneNumber, String message) throws Exception{
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNumber, null, message, null, null);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_SEND_SMS: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
sendBulkTexts();
} else {
Toast.makeText(getActivity(),
"Permission for sending SMSs denied.", Toast.LENGTH_LONG).show();
mCompletionListener.complete(false);
return;
}
}
}
}
}
公共类SendDialog扩展了DialogFragment{
私有静态final int MY_PERMISSIONS_REQUEST_SEND_SMS=1000;
私人阵列列表管理器;
私有数据消息;
私有未完成的McCompletionListener;
私人彩信管理器;
私有位图mBitmap;
私有静态字符串[]mmeditypes;
public SendDialog(ArrayList电话号码、DMessage m、OnFinished侦听器){
mPhoneNumbers=电话号码;
m消息=m;
mcCompletionListener=监听器;
}
公共发送对话框(ArrayList电话号码、DMMessage m、位图b、未完成的侦听器){
mPhoneNumbers=电话号码;
m消息=m;
mcCompletionListener=监听器;
mBitmap=b;
}
公共接口未完成{
无效完成(布尔成功);
}
私有字符串getCautionMessage(){
int numContacts=0;
if(mPhoneNumbers!=null&&mPhoneNumbers.size()>0){
对于(字符串编号:
议员
message.setFromAddress(Utils.getMyPhoneNumber(mContext));
message.setSave(false);
Uri uri = Uri.parse("content://mms-sms/conversations/");
message.setMessageUri(uri);