灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2042回复:0

Android开发之APN网络切换

楼主#
更多 发布于:2012-09-06 13:49


本文介绍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或更高的版本上。


喜欢0 评分0
游客

返回顶部