android自定義發彩信實現(不調用系統發彩信界面)

最近幾天,因為項目需要,發彩信界面不再是調用系統的界面,即不跳轉到短信界面,這個功能起初感覺應該很簡單,但是真正做起來後,發現其實沒有想象中那麼簡單,剛做完項目,趁頭腦清晰,先把代碼寫下來先:

這幾天為瞭這個項目,網上找瞭不少資料,大都資料都差不多,對於如何不跳用系統界面發彩信都有講解,但是這個的前提是apn必須是wap,當如果是net時,因為連接超時而無法發送,正以內發彩信必須通過wap接入點才能發送,即使是在系統界面發彩信時,如果接入點不是wap,則會自動切換過來,待發送完後再切換回去,所以這個模塊的核心,其實就是,如何在調用發彩信時,切換apn至wap,待發送完畢後再切換回去。。。

首先,根據不同移動供應商,需要設置不同的url和proxy

[java] // 電信彩信中心url,代理,端口  
public static String mmscUrl_ct = "http://mmsc.vnet.mobi"; 
public static String mmsProxy_ct = "10.0.0.200"; 
// 移動彩信中心url,代理,端口  
public static String mmscUrl_cm = "http://mmsc.monternet.com"; 
public static String mmsProxy_cm = "010.000.000.172"; 
// 聯通彩信中心url,代理,端口  
public static String mmscUrl_uni = "http://mmsc.vnet.mobi"; 
public static String mmsProxy_uni = "10.0.0.172"; 
 // 電信彩信中心url,代理,端口
 public static String mmscUrl_ct = "http://mmsc.vnet.mobi";
 public static String mmsProxy_ct = "10.0.0.200";
 // 移動彩信中心url,代理,端口
 public static String mmscUrl_cm = "http://mmsc.monternet.com";
 public static String mmsProxy_cm = "010.000.000.172";
 // 聯通彩信中心url,代理,端口
 public static String mmscUrl_uni = "http://mmsc.vnet.mobi";
 public static String mmsProxy_uni = "10.0.0.172";

方法實現如下:

[java] private static List<String> getSimMNC(Context context){ 
        TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);  
        String imsi = telManager.getSubscriberId();  
        if(imsi!=null){  
            ArrayList<String> list = new ArrayList<String>(); 
            if(imsi.startsWith("46000") ||imsi.startsWith("46002")){  
                //因為移動網絡編號46000下的IMSI已經用完,所以虛擬瞭一個46002編號,134/159號段使用瞭此編號   
                //中國移動   
                list.add(mmscUrl_cm); 
                list.add(mmsProxy_cm); 
            }else if(imsi.startsWith("46001")){  
                //中國聯通   
                list.add(mmscUrl_uni); 
                list.add(mmsProxy_uni); 
            }else if(imsi.startsWith("46003")){  
                //中國電信   
                list.add(mmscUrl_ct); 
                list.add(mmsProxy_ct); 
            }  
            shouldChangeApn(context); 
            return list; 
        } 
        return null; 
    } 
private static List<String> getSimMNC(Context context){
  TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
  String imsi = telManager.getSubscriberId();
  if(imsi!=null){
   ArrayList<String> list = new ArrayList<String>();
   if(imsi.startsWith("46000") ||imsi.startsWith("46002")){
    //因為移動網絡編號46000下的IMSI已經用完,所以虛擬瞭一個46002編號,134/159號段使用瞭此編號
    //中國移動
    list.add(mmscUrl_cm);
    list.add(mmsProxy_cm);
   }else if(imsi.startsWith("46001")){
    //中國聯通
    list.add(mmscUrl_uni);
    list.add(mmsProxy_uni);
   }else if(imsi.startsWith("46003")){
    //中國電信
    list.add(mmscUrl_ct);
    list.add(mmsProxy_ct);
   }
   shouldChangeApn(context);
   return list;
  }
  return null;
 }
當當前的apn接入點不是發彩信所需要的wap時,就需要切換:

[java] private static boolean shouldChangeApn(final Context context){ 
         
        final String wapId = getWapApnId(context); 
        String apnId = getApn(context); 
        //若當前apn不是wap,則切換至wap  
        if(!wapId.equals(apnId)){ 
            APN_NET_ID = apnId; 
            setApn(context,wapId); 
            //切換apn需要一定時間,先讓等待2秒  
            try { 
                Thread.sleep(2000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            return true; 
        } 
        return false; 
    } 
private static boolean shouldChangeApn(final Context context){
  
  final String wapId = getWapApnId(context);
  String apnId = getApn(context);
  //若當前apn不是wap,則切換至wap
  if(!wapId.equals(apnId)){
   APN_NET_ID = apnId;
   setApn(context,wapId);
   //切換apn需要一定時間,先讓等待2秒
   try {
    Thread.sleep(2000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   return true;
  }
  return false;
 }
所有的apn信息都是存在數據表裡,可以通過adb pull data/data/com.android.providers.telephony d:/ 直接拷出來,不過前提是手機有root權限:[java] private static String getApn(Context context){ 
        ContentResolver resoler = context.getContentResolver(); 
        String[] projection = new String[]{"_id"}; 
        Cursor cur = resoler.query(Uri.parse("content://telephony/carriers/preferapn"),projection, null, null, null); 
        String apnId = null; 
        if(cur!=null&&cur.moveToFirst()){ 
            do { 
                apnId = cur.getString(cur.getColumnIndex("_id")); 
            } while (cur.moveToNext()); 
        } 
        return apnId; 
    } 
    /**
     * 設置接入點
     * @param id
     */ 
    private static void setApn(Context context ,String id){ 
        Uri uri = Uri.parse("content://telephony/carriers/preferapn");    
        ContentResolver resolver = context.getContentResolver();   
        ContentValues values = new ContentValues();   
        values.put("apn_id", id);   
        resolver.update(uri, values, null, null); 
    } 
    private static String APN_NET_ID = null; 
    /**
     * 取到wap接入點的id
     * @return
     */ 
    private static String getWapApnId(Context context){ 
        ContentResolver contentResolver = context.getContentResolver(); 
        String[] projection = new String[]{"_id","proxy"}; 
        Cursor cur = contentResolver.query(Uri.parse("content://telephony/carriers"), projection, "current = 1", null, null); 
        if(cur!=null&&cur.moveToFirst()){ 
            do { 
                String id = cur.getString(0); 
                String proxy = cur.getString(1); 
                if(!TextUtils.isEmpty(proxy)){ 
                    return id; 
                } 
            } while (cur.moveToNext()); 
        } 
        return null; 
    } 
private static String getApn(Context context){
  ContentResolver resoler = context.getContentResolver();
  String[] projection = new String[]{"_id"};
  Cursor cur = resoler.query(Uri.parse("content://telephony/carriers/preferapn"),projection, null, null, null);
  String apnId = null;
  if(cur!=null&&cur.moveToFirst()){
   do {
    apnId = cur.getString(cur.getColumnIndex("_id"));
   } while (cur.moveToNext());
  }
  return apnId;
 }
 /**
  * 設置接入點
  * @param id
  */
 private static void setApn(Context context ,String id){
  Uri uri = Uri.parse("content://telephony/carriers/preferapn");  
  ContentResolver resolver = context.getContentResolver(); 
  ContentValues values = new ContentValues(); 
  values.put("apn_id", id); 
  resolver.update(uri, values, null, null);
 }
 private static String APN_NET_ID = null;
 /**
  * 取到wap接入點的id
  * @return
  */
 private static String getWapApnId(Context context){
  ContentResolver contentResolver = context.getContentResolver();
  String[] projection = new String[]{"_id","proxy"};
  Cursor cur = contentResolver.query(Uri.parse("content://telephony/carriers"), projection, "current = 1", null, null);
  if(cur!=null&&cur.moveToFirst()){
   do {
    String id = cur.getString(0);
    String proxy = cur.getString(1);
    if(!TextUtils.isEmpty(proxy)){
     return id;
    }
   } while (cur.moveToNext());
  }
  return null;
 }

取wap接入點的id方法中,就是從carriers表中讀取到current=1的條目,隻有這種條目能夠顯示在手機的apn設置中,即:

 

 

接下來這個方法,是處理發彩信請求:

[java] private static boolean sendMMMS(List<String> list,final Context context, byte[] pdu) throws Exception { 
        // HDR_AVLUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage();  
        if(list==null){ 
            myHandler.post(new Runnable() { 
                 
                @Override 
                public void run() { 
                    Toast.makeText(context, "找不到sim卡", Toast.LENGTH_LONG).show(); 
                } 
            }); 
            return false; 
        } 
        String mmsUrl = (String) list.get(0); 
        String mmsProxy = (String) list.get(1); 
        HttpClient client = null; 
        try { 
            URI hostUrl = new URI(mmsUrl); 
            HttpHost target = new HttpHost(hostUrl.getHost(), 
                    hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME); 
            client = AndroidHttpClient.newInstance("Android-Mms/2.0"); 
            HttpPost post = new HttpPost(mmsUrl); 
            ByteArrayEntity entity = new ByteArrayEntity(pdu); 
            entity.setContentType("application/vnd.wap.mms-message"); 
            post.setEntity(entity); 
            post.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT); 
            post.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE); 
 
            HttpParams params = client.getParams(); 
            HttpProtocolParams.setContentCharset(params, "UTF-8"); 
 
            ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsProxy, 
                    80)); 
            HttpResponse response = client.execute(target, post); 
            StatusLine status = response.getStatusLine(); 
            System.out.println("status : " + status.getStatusCode()); 
            if (status.getStatusCode() != 200) { 
                throw new IOException("HTTP error: " + status.getReasonPhrase()); 
            } 
            //彩信發送完畢後檢查是否需要把接入點切換回來  
            if(null!=APN_NET_ID){ 
                setApn(context,APN_NET_ID); 
            } 
            return true; 
 
        } catch (Exception e) { 
            e.printStackTrace(); 
            Log.d(TAG, "彩信發送失敗:"+e.getMessage()); 
            //發送失敗處理  
        } 
        return false; 
    } 
private static boolean sendMMMS(List<String> list,final Context context, byte[] pdu) throws Exception {
  // HDR_AVLUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage();
  if(list==null){
   myHandler.post(new Runnable() {
    
    @Override
    public void run() {
     Toast.makeText(context, "找不到sim卡", Toast.LENGTH_LONG).show();
    }
   });
   return false;
  }
  String mmsUrl = (String) list.get(0);
  String mmsProxy = (String) list.get(1);
  HttpClient client = null;
  try {
   URI hostUrl = new URI(mmsUrl);
   HttpHost target = new HttpHost(hostUrl.getHost(),
     hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
   client = AndroidHttpClient.newInstance("Android-Mms/2.0");
   HttpPost post = new HttpPost(mmsUrl);
   ByteArrayEntity entity = new ByteArrayEntity(pdu);
   entity.setContentType("application/vnd.wap.mms-message");
   post.setEntity(entity);
   post.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT);
   post.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE);

   HttpParams params = client.getParams();
   HttpProtocolParams.setContentCharset(params, "UTF-8");

   ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsProxy,
     80));
   HttpResponse response = client.execute(target, post);
   StatusLine status = response.getStatusLine();
   System.out.println("status : " + status.getStatusCode());
   if (status.getStatusCode() != 200) {
    throw new IOException("HTTP error: " + status.getReasonPhrase());
   }
   //彩信發送完畢後檢查是否需要把接入點切換回來
   if(null!=APN_NET_ID){
    setApn(context,APN_NET_ID);
   }
   return true;

  } catch (Exception e) {
   e.printStackTrace();
   Log.d(TAG, "彩信發送失敗:"+e.getMessage());
   //發送失敗處理
  }
  return false;
 }
發彩信程序主入口:

[java] private static String HDR_VALUE_ACCEPT_LANGUAGE = ""; 
    private static final String HDR_KEY_ACCEPT = "Accept"; 
    private static final String HDR_KEY_ACCEPT_LANGUAGE = "Accept-Language"; 
    private static final String HDR_VALUE_ACCEPT = "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"; 
    /** 
     * 發彩信接口 by liuhanzhi 
     * @param context 
     * @param phone 手機號 
     * @param subject 主題 
     * @param text  文字 
     * @param imagePath 圖片路徑     
     * @param audioPath 音頻路徑 
     */ 
    public static void send(final Context context,String phone,String subject,String text,String imagePath,String audioPath) { 
//      String subject = "測試彩信";  
        Log.v("MmsTestActivity", subject); 
//      String recipient = "18911722352";// 138xxxxxxx  
        SendReq sendRequest = new SendReq(); 
        EncodedStringValue[] sub = EncodedStringValue.extract(subject); 
        if (sub != null && sub.length > 0) { 
            sendRequest.setSubject(sub[0]); 
        } 
        EncodedStringValue[] phoneNumbers = EncodedStringValue 
                .extract(phone); 
        if (phoneNumbers != null && phoneNumbers.length > 0) { 
            sendRequest.addTo(phoneNumbers[0]); 
        } 
        PduBody pduBody = new PduBody(); 
        if(!TextUtils.isEmpty(text)){ 
            PduPart partPdu3 = new PduPart(); 
            partPdu3.setCharset(CharacterSets.UTF_8); 
            partPdu3.setName("mms_text.txt".getBytes()); 
            partPdu3.setContentType("text/plain".getBytes()); 
            partPdu3.setData(text.getBytes()); 
            pduBody.addPart(partPdu3); 
        } 
        if(!TextUtils.isEmpty(imagePath)){ 
            PduPart partPdu = new PduPart(); 
            partPdu.setCharset(CharacterSets.UTF_8); 
            partPdu.setName("camera.jpg".getBytes()); 
            partPdu.setContentType("image/png".getBytes()); 
//      partPdu.setDataUri(Uri.parse("/wp-content/images1/20181013/20120414101424728303.jpg"));  
            partPdu.setDataUri(Uri.fromFile(new File(imagePath))); 
            pduBody.addPart(partPdu); 
        } 
        if(!TextUtils.isEmpty(audioPath)){ 
            PduPart partPdu2 = new PduPart(); 
            partPdu2.setCharset(CharacterSets.UTF_8); 
            partPdu2.setName("speech_test.amr".getBytes()); 
            partPdu2.setContentType("audio/amr".getBytes()); 
            // partPdu2.setContentType("audio/amr-wb".getBytes());  
//          partPdu2.setDataUri(Uri.parse("file://mnt//sdcard//.lv//audio//1326786209801.amr"));  
            partPdu2.setDataUri(Uri.fromFile(new File(audioPath))); 
            pduBody.addPart(partPdu2); 
        } 
 
        sendRequest.setBody(pduBody); 
        final PduComposer composer = new PduComposer(context, sendRequest); 
        final byte[] bytesToSend = composer.make(); 
        final List<String> list = getSimMNC(context); 
        Thread t = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                //因為在切換apn過程中需要一定時間,所以需要加上一個重試操作  
                int retry = 0; 
                do { 
                    Log.d(TAG, "重試次數:"+(retry+1)); 
                    try { 
                        if (sendMMMS(list, context, bytesToSend)) { 
                            myHandler.post(new Runnable() { 
 
                                @Override 
                                public void run() { 
                                    Toast.makeText(context, "彩信發送成功!", 
                                            Toast.LENGTH_LONG).show(); 
                                } 
                            }); 
                            return; 
                        } 
                        retry++; 
                        Thread.sleep(2000); 
                    } catch (Exception e) { 
                        e.printStackTrace(); 
                    } 
                } while (retry < 5); 
                myHandler.post(new Runnable() { 
                    @Override 
                    public void run() { 
                        Toast.makeText(context, "彩信發送失敗!", Toast.LENGTH_LONG).show(); 
                    } 
                }); 
            } 
        }); 
        t.start(); 
 
    } 

 
摘自 agods–足跡
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *