Android代码设置APN

什么是APN?

APN(Access Point Name)中文全称叫接入点。APN指一种网络接入技术,是通过手机上网时必须配置的一个参数,它决定了手机通过哪种接入方式来访问网络。APN用来标识GPRS的业务种类,目前分为两大类:CMWAP(通过GPRS访问WAP业务)、CMNET(除了WAP以外的服务目前都用CMNET,比如连接因特网等)。

APN手机里的位置

不同手机可能位置不一样,我使用的测试机是红米3S,位置是:设置->双卡和移动网络->接入点名称。或者可以直接在设置里直接搜索“APN”。我是在测试的时候才需要来这里看动态添加APN是否成功。

这里需要提前说明,代码实现设置APN需要程序拥有系统权限,如何拥有系统权限呢?你需要去找个工具给自己用AS build的apk进行系统签名,这种系统签名工具我之前在CSDM上看到过,如果需要的话可以去搜一下。另一点就是需要SIM卡,如果测试机没有SIM卡的话就没办法进行这方面的测试了。

Android系统中,对于APN网络的API是隐藏的,因此获取手机的APN设置,需要通过ContentProvider来进行数据库查询,查询的URI地址是:
取得全部的APN列表:content://telephony/carriers;
取得当前设置的APN:content://telephony/carriers/preferapn;
取得current=1的APN:content://telephony/carriers/current;

下面是代码实现简单介绍:
通过cr这个游标对象可以进行手机里面APN信息的查询,下面代码中的“ErrorApplication.getContext()”其实只是一个context对象,我实际代码中是这样写,把它换成其他合适的this或者你需要的context对象都可以。
// 检查当前连接的APN

Cursor cr = ErrorApplication.getContext().getContentResolver().query(APN_URI, null, null, null, null);
        while (cr != null && cr.moveToNext()) {
    if(cr.getString(cr.getColumnIndex("apn")).equals("abc")){
                APN.hasAPN=true;
                break;
            }
        }
    }

获取SIM卡信息:APN中的某些属性在这些信息里面

protected String getSIMInfo() {
    TelephonyManager iPhoneManager = (TelephonyManager) ErrorApplication.getContext()
            .getSystemService(Context.TELEPHONY_SERVICE);
    return iPhoneManager.getSimOperator();
}

添加接入点:

public int addAPN() {
        int id = -1;
        String NUMERIC = getSIMInfo();
        if (NUMERIC == null) {
            return -1;
        }
        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();
        values.put("name", "专用APN");                                  //apn中文描述
        values.put("apn", "unim2m.njm2mapn1");                                     //apn名称
        values.put("type", "default");                            //apn类型
        values.put("numeric", NUMERIC);
        values.put("mcc", NUMERIC.substring(0, 3));
        values.put("mnc", NUMERIC.substring(3, NUMERIC.length()));
        values.put("proxy", "");                                        //代理
        values.put("port", "");                                         //端口
        values.put("mmsproxy", "");                                     //彩信代理
        values.put("mmsport", "");                                      //彩信端口
        values.put("user", "");                                         //用户名
        values.put("server", "");                                       //服务器
        values.put("password", "");                                     //密码
        values.put("mmsc", "");                                          //MMSC
        Cursor c = null;
        Uri newRow = resolver.insert(APN_URI, values);
        if (newRow != null) {
            c = resolver.query(newRow, null, null, null, null);
            int idIndex = c.getColumnIndex("_id");
            c.moveToFirst();
            id = c.getShort(idIndex);
        }
        if (c != null)
            c.close();
        return id;
    }

设置接入点:

public void SetAPN(int id) {
ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put(“apn_id”, id);
resolver.update(CURRENT_APN_URI, values, null, null);
}

下面是封装成一个工具类的完整代码:

public class APN {
    public static boolean hasAPN;
    // 新增一个cmnet接入点
    public void APN(){
        checkAPN();
    }
    public int addAPN() {
        int id = -1;
        String NUMERIC = getSIMInfo();
        if (NUMERIC == null) {
            return -1;
        }
        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();
        values.put("name", "专用APN");                                  //apn中文描述
        values.put("apn", "abc");                                     //apn名称
        values.put("type", "default");                            //apn类型
        values.put("numeric", NUMERIC);
        values.put("mcc", NUMERIC.substring(0, 3));
        values.put("mnc", NUMERIC.substring(3, NUMERIC.length()));
        values.put("proxy", "");                                        //代理
        values.put("port", "");                                         //端口
        values.put("mmsproxy", "");                                     //彩信代理
        values.put("mmsport", "");                                      //彩信端口
        values.put("user", "");                                         //用户名
        values.put("server", "");                                       //服务器
        values.put("password", "");                                     //密码
        values.put("mmsc", "");                                          //MMSC
        Cursor c = null;
        Uri newRow = resolver.insert(APN_URI, values);
        if (newRow != null) {
            c = resolver.query(newRow, null, null, null, null);
            int idIndex = c.getColumnIndex("_id");
            c.moveToFirst();
            id = c.getShort(idIndex);
        }
        if (c != null)
            c.close();
        return id;
    }

    protected String getSIMInfo() {
        TelephonyManager iPhoneManager = (TelephonyManager) ErrorApplication.getContext()
                .getSystemService(Context.TELEPHONY_SERVICE);
                return iPhoneManager.getSimOperator();
    }
    // 设置接入点
    public void SetAPN(int id) {
        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();
        values.put("apn_id", id);
        resolver.update(CURRENT_APN_URI, values, null, null);
        }
    public void checkAPN() {
        // 检查当前连接的APN
        Cursor cr = ErrorApplication.getContext().getContentResolver().query(APN_URI, null, null, null, null);
        while (cr != null && cr.moveToNext()) {
         if(cr.getString(cr.getColumnIndex("apn")).equals("abc")){
                APN.hasAPN=true;
                break;
            }
        }
    }
}

在主活动的调用:

APN apn=new APN();
apn.checkAPN();
if (!APN.hasAPN) {
    apn.SetAPN(apn.addAPN());
}

补充解释,一开始实现功能之后,发现每次打开程序,都会创建一个APN出来,想一想就很不舒服,几次操作之后设置那里APN的列表就会一大串。于是添加了一点改进,设置各静态变量hasAPN,每次主活动创建后,先通过checkAPN里面查找,看有没有已存在的我们需要的APN,然后改变hasAPN的值,如果没有我们才去创建。

参考链接:
http://blog.csdn.net/leilu2008/article/details/8900584
https://baike.baidu.com/item/apn/96667?fr=aladdin
http://blog.csdn.net/lll1204019292/article/details/52260817

2017.09.16续:

上面写的东西基本可以实现我想要的功能了,不过不久老板娘就提出新的需求,她想要设置多个APN,然后根据网络是否可用去动态选择可用的APN。想了一想发现原来封装的工具类还不够方便,于是添加多个参数,把想要的APN当参数传进去,再去调用checkAPN()、addAPN()、setAPN()。代码如下:
/**
 * Created by Jim斌 on 2017/8/21.
 */

public class APN {
    public static boolean hasAPN;
    private static int cmiot_ID,apn_1_ID,apn_2_ID,apn_3_ID;

    // 新增一个cmnet接入点
    public void APN(){
//        checkAPN();
    }
    public int addAPN() {
        int id = -1;
        String NUMERIC = getSIMInfo();
        if (NUMERIC == null) {
           return -1;
        }
        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();

//        SIMCardInfo siminfo = new SIMCardInfo(MainActivity.this);
        // String user = siminfo.getNativePhoneNumber().substring(start);

        values.put("name", "cmiot");                                  //apn中文描述
        values.put("apn", "cmiot");                                     //apn名称
        values.put("type", "default");                            //apn类型
        values.put("numeric", NUMERIC);
        values.put("mcc", NUMERIC.substring(0, 3));
        values.put("mnc", NUMERIC.substring(3, NUMERIC.length()));
        values.put("proxy", "");                                        //代理
        values.put("port", "");                                         //端口
        values.put("mmsproxy", "");                                     //彩信代理
        values.put("mmsport", "");                                      //彩信端口
        values.put("user", "");                                         //用户名
        values.put("server", "");                                       //服务器
        values.put("password", "");                                     //密码
        values.put("mmsc", "");                                          //MMSC

        Cursor c = null;
        Uri newRow = resolver.insert(APN_URI, values);
        if (newRow != null) {
            c = resolver.query(newRow, null, null, null, null);
            int idIndex = c.getColumnIndex("_id");
            c.moveToFirst();
            id = c.getShort(idIndex);
        }
        if (c != null)
            c.close();
        return id;
    }
    public int addAPN(String name,String apn) {
        int id = -1;
        String NUMERIC = getSIMInfo();
        if (NUMERIC == null) {
            return -1;
        }

        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();

//        SIMCardInfo siminfo = new SIMCardInfo(MainActivity.this);
        // String user = siminfo.getNativePhoneNumber().substring(start);

        values.put("name", name);                                  //apn中文描述
        values.put("apn", apn);                                     //apn名称
        values.put("type", "default");                            //apn类型
        values.put("numeric", NUMERIC);
        values.put("mcc", NUMERIC.substring(0, 3));
        values.put("mnc", NUMERIC.substring(3, NUMERIC.length()));
        values.put("proxy", "");                                        //代理
        values.put("port", "");                                         //端口
        values.put("mmsproxy", "");                                     //彩信代理
        values.put("mmsport", "");                                      //彩信端口
        values.put("user", "");                                         //用户名
        values.put("server", "");                                       //服务器
        values.put("password", "");                                     //密码
        values.put("mmsc", "");                                          //MMSC
        Cursor c = null;
        Uri newRow = resolver.insert(APN_URI, values);
        if (newRow != null) {
            c = resolver.query(newRow, null, null, null, null);
            int idIndex = c.getColumnIndex("_id");
            c.moveToFirst();
            id = c.getShort(idIndex);
        }
        if (c != null)
            c.close();
        return id;
    }
    protected String getSIMInfo() {
        TelephonyManager iPhoneManager = (TelephonyManager) ErrorApplication.getContext()
                .getSystemService(Context.TELEPHONY_SERVICE);
        Log.d("abc", "getSIMInfo:"+iPhoneManager.getSimOperator());
        return iPhoneManager.getSimOperator();
    }

    // 设置接入点
    public void SetAPN(int id) {
        ContentResolver resolver = ErrorApplication.getContext().getContentResolver();
        ContentValues values = new ContentValues();
        values.put("apn_id", id);
        resolver.update(CURRENT_APN_URI, values, null, null);
        // resolver.delete(url, where, selectionArgs)
    }
    public void checkAPN(String apn) {
        // 检查当前连接的APN
        Cursor cr = ErrorApplication.getContext().getContentResolver().query(APN_URI, null, null, null, null);

        Log.d("abc", "cr" + cr);
        while (cr != null && cr.moveToNext()) {
            if(cr.getString(cr.getColumnIndex("apn")).equals(apn)){
                APN.hasAPN=true;
                Log.d("APN.hasAPN在checkAPN()中", ": "+APN.hasAPN);
                break;
            }
        }
        cr.close();
    }
}

判断网络是否可用工具类如下:

/**
     * 判断MOBILE网络是否可用
     * @param context
     * @return
     * @throws Exception
     */
    public static boolean isMobileDataEnable(Context context) throws Exception {
        ConnectivityManager connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        boolean isMobileDataEnable = false;

        isMobileDataEnable = connectivityManager.getNetworkInfo(
                ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();

        return isMobileDataEnable;
    }

然后根据网络状态是否可用去设置APN的代码我就不贴出来了,就组装一下就可以。**

这里有个地方需要注意,是我之前踩到的坑:

**
在修改APN后,马上去判断网络是否可用,这个时候是不准的,因为设置完APN后到他生效能上网,手机需要一定的时间。在APN设置生效后再去判断这个时候判断的结果才是正确的。测试了很多次后发现,在我的测试机至少需要等待7秒它才会生效,不同的机子可能情况有出入。一开始我还以为判断移动网络是否可用的工具类是错的。。等待使用的方法都随便啦,Thread.sleep()阿定时器都OK,判断多个的话个人感觉还是定时器用着舒服些。

你可能感兴趣的:(android)