2025-05-17

本文介紹Android平臺中關於APN網絡切換的相關知識。
 
APN(Access Point Name),即“接入點名稱”,用來標識GPRS的業務種類,目前分為兩大類:CMWAP(通過GPRS訪問WAP業務)、CMNET(除瞭WAP以外的服務目前都用CMNET,比如連接因特網等)。
 
APN的英文全稱是Access Point Name,中文全稱叫接入點,是您在通過手機上網時必須配置的一個參數,它決定瞭您的手機通過哪種接入方式來訪問網絡。
 
移動手機的默認上網配置有兩種:CMWAP和CMNET。一些使用移動辦公的大客戶,通常會使用專用APN,其接入點隨意定義,隻要和該省運營商其他APN不沖突即可。
   
CMWAP也叫移動夢網,通過該接入點可接入一個比較大的移動私網,網內有大量的手機應用下載及資源訪問。因為CMWAP不接入互聯網,隻接入移動運營商的私網,所以流量費用比較低廉。
   
CMNET也叫GPRS連接互聯網,通常每個省的運營商會提供若幹個Internet出口以供CMNET撥號用戶使用。其流量費用較CMWAP要高一些。
   
目前國內銷售的手機,如果是非智能機,通常已配置好CMWAP連接,智能機通常會配置CMWAP和CMNET連接。如需手動添加這些配置,請參考手機說明書。
   
專有APN在功能上可以和Internet的VPN做類比,實際上他就是基於GPRS的VPN網絡。
 
專有APN常見組網方式
1,運營商部署一條專線接入到企業的網絡中,局端和企業端路由器之間采用私有IP進行連接。
 
    2,局端互連路由器與GGSN采用GRE隧道連接。
 
專有APN的幾個重要特點:
1,除非運營商分配一個Internet IP地址,否則計算機沒有任何辦法通過Internet訪問該APN中的主機。
 
2,隻有手機卡號在APN中的白名單之列,該手機才可以接入該APN。
 
3,企業客戶可以建立一套RADIUS和DHCP服務器,GGSN向RADIUS服務器提供用戶主叫號碼,采用主叫號碼和用戶賬號相結合的認證方式;用戶通過認證後由DHCP服務器分配企業內部的靜態IP地址。補充:該認證方式不一定適合於每個省的運營商,這取決於該省運營商的APN管理平臺。
 
GPRS專網系統終端上網登錄服務器平臺的流程為:
  
1)用戶發出GPRS登錄請求,請求中包括由運營商為GPRS專網系統專門分配的專網APN;
 
  
2)根據請求中的APN,SGSN向DNS服務器發出查詢請求,找到與企業服務器平臺連接的GGSN,並將用戶請求通過GTP隧道封裝送給GGSN;
 
  
3)GGSN將用戶認證信息(包括手機號碼、用戶賬號、密碼等)通過專線送至Radius進行認證;
 
  
4)Radius認證服務器看到手機號等認證信息,確認是合法用戶發來的請求,向DHCP服務器請求分配用戶地址;
 
  
5)Radius認證通過後,由Radius向GGSN發送攜帶用戶地址的確認信息;
 
  
6)用戶得到瞭IP地址,就可以攜帶數據包,對GPRS專網系統信息查詢和業務處理平臺進行訪問。
 
下面是相關代碼:
 
  public void openAPN(){   
List list = getAPNList();  
        for (APN apn : list) {  
            ContentValues cv = new ContentValues();  
            cv.put("apn", APNMatchTools.matchAPN(apn.apn));  
            cv.put("type", APNMatchTools.matchAPN(apn.type));  
            getContentResolver().update(uri, cv, "_id=?", new String[]{apn.id});  
        }  
   }
 

  public void closeAPN(){   
List list = getAPNList(); 
       
        for (APN apn : list) {      
            ContentValues cv = new ContentValues();  
            cv.put("apn", APNMatchTools.matchAPN(apn.apn)+"mdev");  
            cv.put("type", APNMatchTools.matchAPN(apn.type)+"mdev");  
            getContentResolver().update(uri, cv, "_id=?", new String[]{apn.id});  
        }   
    }   
 

   private List getAPNList(){  
String tag = "Main.getAPNList()";  
        //current不為空表示可以使用的APN  
        String projection[] = {"_id,apn,type,current"};  
        Cursor cr = this.getContentResolver().query(uri, projection, null, null, null);  
        List list = new ArrayList();  
         
        while(cr!=null && cr.moveToNext()){  
            Log.d(tag, cr.getString(cr.getColumnIndex("_id")) + " " + cr.getString(cr.getColumnIndex("apn")) + " " + cr.getString(cr.getColumnIndex("type"))+ " " + cr.getString(cr.getColumnIndex("current")));  
            APN a = new APN();  
            a.id = cr.getString(cr.getColumnIndex("_id"));   
            a.apn = cr.getString(cr.getColumnIndex("apn"));  
            a.type = cr.getString(cr.getColumnIndex("type"));  
            list.add(a);  
        }  
         
        if(cr!=null)  
        cr.close();  
        return list;  
    }  
         
    public static class APN{  
        String id;  
        String apn;  
        String type;  
    } 

 
    /**
     * @Name: setDefaultApn
     * @Description: 設置默認APN
     * @param apnId
     * @return boolean 返回類型
     * @throws
     */
    public boolean setDefaultApn(int apnId) {
        boolean res = false;
        ContentResolver resolver = context.getContentResolver();
        ContentValues values = new ContentValues();
        values.put("apn_id", apnId);

        try {
            resolver.update(PREFERRED_APN_URI, values, null, null);
            Cursor c = resolver.query(PREFERRED_APN_URI, new String[] { "name",
                    "apn" }, "_id=" + apnId, null, null);
            if (c != null) {
                res = true;
                c.close();
            }
        } catch (SQLException e) {

        }
        return res;
}

 
    /**
     * 得到當前使用的APN
     * @return
     */
    public ApnNode getDefaultAPN() {
        String id = "";
        String apn = "";
        String name = "";
        String type = "";
        ApnNode apnNode = new ApnNode();
        Cursor mCursor = context.getContentResolver().query(PREFERRED_APN_URI,
                null, null, null, null);
        if (mCursor == null) {
            return null;
        }
        while (mCursor != null && mCursor.moveToNext()) {
            id = mCursor.getString(mCursor.getColumnIndex("_id"));
            name = mCursor.getString(mCursor.getColumnIndex("name"));
            apn = mCursor.getString(mCursor.getColumnIndex("apn"))
                    .toLowerCase();
            type = mCursor.getString(mCursor.getColumnIndex("type"))
                    .toLowerCase();
        }
        OLD_APN_ID = Integer.valueOf(id);
        apnNode.setName(name);
        apnNode.setApn(apn);
        apnNode.setType(type);
       
        System.out.println("old_name:" + name + "–old_apn:" + apn + "–old_type:" + type);
       
        return apnNode;
}

   
    /**
     * @Name: SwitchApn
     * @Description: 轉換APN狀態
     * @param 設定文件
     * @return void 返回類型
     * @throws
     */
    public void SwitchApn() {
        switch (GetCurrentNetType()) {
        case NET_3G:
            if (!IsCurrentEmergencyApn()) {
                EM_APN_ID = IsEmergencyApnExisted(EMERGENCY_APN);
                System.out.println(EM_APN_ID);
               
                if (EM_APN_ID == -1) {
                    setDefaultApn(AddEmergencyApn());
                } else {
                    setDefaultApn(EM_APN_ID);
                }
            }
           
            break;
        case NET_WIFI:
            break;
        case NET_OTHER:
            break;
        default:
            break;
        }
}

   
public final class APNMatchTools {  
    public static class APNNet{  
        /* 
        * 中國移動cmwap 
        */ 
        public static String CMWAP = "cmwap";  
        /*
        * 中國移動cmnet 
        */ 
        public static String CMNET = "cmnet";  
        //中國聯通3GWAP設置 中國聯通3G因特網設置 中國聯通WAP設置 中國聯通因特網設置  
        //3gwap 3gnet uniwap uninet  
        /*
        * 3G wap 中國聯通3gwap APN 
        */ 
        public static String GWAP_3 = "3gwap";  
        /* 
        * 3G net 中國聯通3gnet APN 
        */ 
        public static String GNET_3="3gnet";  
        /** 
        * uni wap 中國聯通uni wap APN 
        */ 
        public static String UNIWAP="uniwap";  
        /** 
        * uni net 中國聯通uni net APN 
        */ 
        public static String UNINET="uninet";  
         
        }  
         
        public static String matchAPN(String currentName) {  
            if("".equals(currentName) || null==currentName){  
            return "";  
        }  
         
        currentName = currentName.toLowerCase();  
         
        if(currentName.startsWith(APNNet.CMNET))  
            return APNNet.CMNET;  
        else if(currentName.startsWith(APNNet.CMWAP))  
            return APNNet.CMWAP;  
        else if(currentName.startsWith(APNNet.GNET_3))  
            return APNNet.GNET_3;  
        else if(currentName.startsWith(APNNet.GWAP_3))  
            return APNNet.GWAP_3;  
        else if(currentName.startsWith(APNNet.UNINET))  
            return APNNet.UNINET;  
        else if(currentName.startsWith(APNNet.UNIWAP))  
            return APNNet.UNIWAP;  
        else if(currentName.startsWith("default"))  
            return "default";  
        else return "";  
        // return currentName.substring(0, currentName.length() – SUFFIX.length());   
    }  
}  

 
<!– 開關APN的權限 –>
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />

   
  對於Android APN接入點相關的開發,有一個不錯的開源項目APNDroid的源代碼本地下載,裡面包含瞭一個不錯的Widget框架,大傢可以通過APNDroid源碼學習到有關接入點的相關問題,可以解決GPRS,尤其是國內的CMNET、CMWAP的切換和管理。工程API Level為3,可以運行在Android 1.5或更高的版本上。
 
下載地址:點擊下載http://up.aiwalls.com/2012/0330/20120330114042736.zip

 
完畢。^_^
 

 

摘自  HarHar
 

發佈留言

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