开发初衷
很久之前做一键登录校园网以失败告终,最近看By_syk大神的文章By_syk简书写的一键登录校园网,很受鼓舞,于是自己动手实验了一下,By_syk的校园网系统和我们的是同一个系统(很神奇),我们学校的校园网也是按流量计费,所以每个人都会有一个帐号,然后连接校园网之后使用这个帐号登录才能使用,由于每次都要登录比较麻烦,所以才会考虑写简单的小工具。
开发原型
做一个简单的APP,提供通知栏瓷片或者快捷方式登录校园网,同时可以提供流量统计等功能(在下一版本考虑)
第一阶段截图
可以看到第三排第二个图标就是我们的校园网登录按钮(这里由于我对Quick TIle不太熟悉,有一些小问题,不影响使用)
这里写图片描述
下面是具体信息页面,只上传一个看看
**
一.分析登录接口
**
首先我们进入我们的校园网登录页面
我使用Chrome的开发者工具来分析网站,发现有个Ipv6地址字段,是获取本机的Ipv6地址上传,于是访问了一下手机登录页面,也就是59.67.0.245/a30.html(本地址只能在校内访问),发现没有该字段,所以打算使用这个页面来抓包
访问59.67.0.245/a30.html输入账号密码,打开浏览器网站分析工具(快捷键F12)切换到开发者工具network选项卡进行抓包,记得要勾选 ️Preserve log 选项进行长连接记录日志。
当点击校园网登录按钮的时候,所有的数据都被开发者工具记录下来,我们选择a30.html这个页面进行分析,这个是post我们的账号密码数据的页面,一般会列在第一位

在这个页面header选项卡里我们可以看到
Request URL:http://59.67.0.245/a30.htm
这样一行,这也就是我们的数据将要post到的地方,那我们的数据在哪呢?对,就是下面打马赛克的那一块,Form Data(表单数据),可以看到一共有8个数据,第一个DDDDD是学号(网站的开发者还真是随便命名),第二个打马赛克当然是密码啦,另外R1,R2,R6,R7,para,0MKKey初步判断为定值
| 字段 | 值 |
|---|---|
| DDDDD | 15104413 |
| upass | ××××××××××× |
| R1 | 0 |
| R2 | |
| R6 | 1 |
| R7 | 0 |
| para | 00 |
| 0MKKey | 123456 |
那我下面列出了本次我们需要提交的值
| 字段 | 值 |
|---|---|
| DDDDD | 15104413 |
| upass | ××××××××××× |
| R1 | 0 |
| R2 | |
| R6 | 1 |
| R7 | 0 |
| para | 00 |
| 0MKKey | 123456 |
在这里我们的密码并没有通过任何方式加密,所以我也就不研究源码了
直接使用postman(一款chrome插件)进行测试
打开postman,第一步选择post方式,第二步填入我们刚才所找到的请求url,然后就是填入表中所列的form,点击蓝色send按钮后,出现PC登录成功页面,说明已经登录成功,这也就意味着我们的测试成功了,我们可以准备开始写代码了。
**
二.准备 APP 蓝图
**
这里我们使用幕布(脑图)分析一下,我们的APP分为3个页面,状态,账号和充值(本篇文章只讲状态里的登录部分)
一键登录的按钮是根据是否连接校园路由器决定的,但是在代码中可能这部分不会判断(也就是请求一下59.67.0.245这个页面,如果成功说明当前连接着校园网,否则连接的不是校园网),为了简单起见,我们选择连接上wifi之后,就可以登录,然后如果不通过就显示登录失败。
下面准备开发,这里我使用的开发环境是deepin15系统下的Android Studio2.3 。
配置依赖
//网络请求
compile 'com.squareup.okhttp3:okhttp:3.8.1'
//Material Design引导页面
compile 'agency.tango.android:material-intro-screen:0.0.5'
//Design库
compile 'com.android.support:design:25.1.0'
配置权限
<!--网络-->
<uses-permission android:name="android.permission.INTERNET" />
<!--网络状态读取-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
有了这些我们就可以做登录操作了(先实现核心功能)
三.核心代码
1.第一步,我们把要post的数据单独写一个文件
文件名:Data.java
public class Data {
//post地址
public static final String post_url = "http://59.67.0.245/a70.htm";
//固定参数
public static final String R1 = "0";
public static final String R2 = "";
public static final String R7 = "0";
public static final String para = "00";
public static final String MKKey = "123456";
public static final String R6 = "1";
}
2.第二步,新建类,里面包含两个静态方法,第一个是检查网络状态,第二个是登录
获取网络状态
//3种网络状态(wifi链接,gprs链接,断网)
private static final int NETWORK_WIFI_CONNECTION = 1;
private static final int NETWORK_MOBILE_CONNECTION = 2;
private static final int NETWORK_DISCONNECTION = 0;
//获取网络状态
public static int getNetWorkStatus(Context context) {
//连接管理器对象
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
//如果连接管理器不为null
if (connectivityManager != null) {
//通过连接管理器获取网络连接状态
NetworkInfo networkInfo = connectivityManager
.getActiveNetworkInfo();
//如果网络状态不为null并且网络已经连接
if (networkInfo != null && networkInfo.isConnected()) {
//根据网络信息状态获取连接种类
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
return NETWORK_WIFI_CONNECTION;
}
return NETWORK_MOBILE_CONNECTION;
}
}
//返回未连接
return NETWORK_DISCONNECTION;
}
登录核心代码
//返回给调用者登录状态
static int status = 0;
public static int LoginNetWork(final Context mContext) {
//这里是读取文件中储存的账号密码并解密的过程(使用base64加密)
SharedPreferences sharedPreferences = mContext.getSharedPreferences("data",MODE_PRIVATE);
String id = new String(Base64.
decode(sharedPreferences.getString("id","0"),Base64.DEFAULT));
String pwd = new String(Base64.
decode(sharedPreferences.getString("pwd","0"),Base64.DEFAULT));
//初始化okhttp的客户端
OkHttpClient client = new OkHttpClient();
//填写表单,如果APP自己用,账号密码可以写死,而不需要从保存的数值里读取
FormBody formBody = new FormBody.Builder()
.add("DDDDD", id)
.add("R1", Data.R1)
.add("R2", Data.R2)
.add("R7", Data.R7)
.add("upass", pwd)
.add("para", Data.para)
.add("0MKKey", Data.MKKey)
.add("R6", Data.R6)
.build();
//将表单提交到url
Request request=new Request.Builder().url(Data.post_url).post(formBody).build();
client.newCall(request).enqueue(new Callback() {
//请求失败回调
@Override
public void onFailure(Call call, IOException e) {
status = -1;
}
//请求成功回调
@Override
public void onResponse(Call call, Response response) throws IOException {
status = 1;
}
});
//将状态返回给调用者
return status;
啊,猝不及防就结束了?
没错就是这样,使用了Okhttp让请求变得更简单,剩下的,就是调用的过程咯
写一个Activity,名字叫ShortActivity,并且配置他为启动器,这样我们就有了一个一键登录的图标,可以放在桌面上
<activity android:name=".ShortActivity"
android:label="快捷登录"
android:theme="@style/myTransparent"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3.最后一步吧,在shortActivity里调用登录方法
//这是他的onCreate方法,不需要界面,直接登录,随后自己finish掉自己
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在这里我没有写检查网络的代码,当然也非常简单,调用我们写好的方法,根据返回值来判断是不是需要开放登录
//根据login方法的返回值确定是否登录成功
if(CheckWiFiANDLogin.LoginNetWork(this)==1){
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show();
}
finish();
}
现在可以运行试试了
此处没有截图……
连接校园网,点击登录的图标就可以登录
就这样就结束了么?
应该没毛病啊Android4.0 - Android 8.0都兼容了
老板让你兼容到Android2.0!!!
日你MMP的2.0
在Android日益发展更迭的版本中,有这么一个版本(7.0),新增加了Quilk Setting TIle功能,这是个什么功能呢,就是在通知栏下拉的列表中,添加自定义的设置瓷片,达到快速设置的功能,所以叫快速设置瓷片
对,就是这个样子
我们来实现更高大上的操作方式吧
不过很遗憾,大部分国产的Android Rom都被定制的不成样子,根本就没有这个功能,所以这个也只能在原生的系统上体验了。
如果你想体验的话,不妨试试刷机原生系统
宝宝这里是小米note 标准版 ,系统是Lineage os Android7.1.2
实现QST首先要在清单文件中注册服务
//配置一些必须的参数
<service
android:name=".Service.QSTileService"
android:icon="@drawable/ic_action_wifi2"
android:label="@string/app_name"
//必须 android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
//必须
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
下面实现这个服务
/**
* 快速设置系统磁块
* Created by surine on 17-7-6.
*/
//Android7.0使用注解
@SuppressLint("NewApi")
public class QSTileService extends TileService {
int net_status = 0;
private static final String SERVICE_STATUS_FLAG = "serviceStatus";
private static final String PREFERENCES_KEY = "com.google.android_quick_settings";
/**
* 这个方法是打开通知栏的时候进行的处理
* 比如说我们这个情况就是打开通知栏判断网络有没有连接
* 连接了就可用,没连接就不可用
*/
@Override
public void onStartListening() {
//如果网络未连接或者gprs网络,设置图块不可见
if (CheckWiFiANDLogin.getNetWorkStatus(this) == 0 || CheckWiFiANDLogin.getNetWorkStatus(this) == 2) {
//我们自定义一个更新磁块方法
updateTile("校园网未连接", false);
} else {
updateTile("校园网已连接", true);
}
}
/**
* 当磁块点击了会发生什么情况
*/
@Override
public void onClick() {
Log.d("QS", "Tile tapped");
//开一个子线程来执行要发生的逻辑
new Thread(new Runnable() {
@Override
public void run() {
//没错,就是登录,并且返回登录状态
if(CheckWiFiANDLogin.LoginNetWork(QSTileService.this) == -1){
updateTile("登录失败",true);
}else{
updateTile("登录成功",true);
}
}
}).start();
}
// 更新瓷片方法
private void updateTile(String title,boolean b) {
//获取瓷片
Tile tile = this.getQsTile();
int newState;
// 改变瓷片活跃度
if (b){
newState = Tile.STATE_ACTIVE;
}else{
newState = Tile.STATE_UNAVAILABLE;
}
// 设置标签,图标,活跃度等
tile.setLabel(title);
tile.setState(newState);
// 刷新
tile.updateTile();
}
}
本宝宝也是第一次接触这个功能,所以不太会,根据Google Code Lab提供的方法简单实现了一下,不过还有些ui上的小bug,不影响使用
到这里我们的瓷片也已经做好了,一个简单的登录校园网APP已经做好了
以后终于不用使用浏览器登录了。
四.写在最后
本篇文章主要讲解了分析抓包,测试抓包,利用抓包实现实用功能
在下一篇文章中,我们将利用抓包进行更多酷炫的操作
在这里很感谢By_syk大佬,在酷安遇到他,很巧在简书也遇到了他,他的文章给了我很大的帮助。