热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从零开始学会做一个简单的APP

本人是矿大学信息安全的大三狗,混了两年日子之后幡然醒悟决定做些自己早就想做的事情,学校的联通宽带是按时长收费的,但是每次查询已用时长和所扣费用步骤都十分的繁琐,大二的时候都想着要自己做一个APP

本人是矿大学信息安全的大三狗,混了两年日子之后幡然醒悟决定做些自己早就想做的事情,学校的联通宽带是按时长收费的,但是每次查询已用时长和所扣费用步骤都十分的繁琐,大二的时候都想着要自己做一个APP来帮助大家减少这些繁琐的步骤,终于拖了半年多才开始做。从只有一点Java基础到最后做出来可用的APP只用了一个星期的时间,以下是干货内容。

我们最先要上的是成果图,还有在学校发的帖子:http://tieba.baidu.com/p/4233858160?pid=81256661492&cid=0#81256661492


首先我们先看一下正常的查询步骤,第一步,登陆网上营业厅,还要输入繁琐的宽带账户,的确是比较麻烦。


第二步以及以后,反正就是点点点,就不讲解了。





(加载比较慢不好意思,一月份因为没有用所以没有数据,就拿去年12月的代替吧。)

然后我要怎么做呢,首先我知道应该用网络爬虫,我就百度怎么用Java写一个爬虫,然后知道了服务器传输数据都是用的post和get方法,然后在浏览器里面使用合适的工具来将想要的包抓取一下,我学习使用的是火狐浏览器的插件firebug,真的是非常好用的工具推荐给大家。


至于在实际动手写的过程中走过许多许多弯路,最后真正实现了以后才发现其实是很简单。以下开始讲电脑上Java的具体实现。

先讲一下最基本的原理,我们用一个httpclient包中的httpclient帮我们处理COOKIEs,COOKIEs就是一个网站的通用登录凭证,一次登录凭借COOKIE访问其他页面不用再次登录。我们首先在登录界面登录,再访问查询的页面,应该就能得到想要的数据,这是基本思想。

首先我们先观察登陆的时候是怎么给服务器发送数据的。

其中几个参数意义不明,我换其他账号用相同的参数get过去是一样的,所以我们构造一个url传送给服务器进行验证即可。

以下是Java代码中构造的一段代码(Android中自带的org.apache包中好像没有这个构造函数了,所以还是直接写一个url上去比较方便。)

      /**

       *登陆

       *生成uriget方法传递过去即可

       */

      URIuri=new URIBuilder()

            .setScheme("https")

            .setHost("uac.10010.com")

            .setPath("/portal/Service/MallLogin")

            .setParameter("callback","jQuery17204165900954174946_1450622603532")

            .setParameter("redirectURL","http%3A%2F%2Fwww.10010.com")

            .setParameter("userName","051602198839")//用户名

            .setParameter("password","xxxxxx")//密码

            .setParameter("pwdType","01")

            .setParameter("productType","04")

            .setParameter("redirectType","01")

            .setParameter("areaCode","350")

            .setParameter("arrcity","%E5%BE%90%E5%B7%9E")

            .setParameter("_","1450622609168")

            .build();//生成想要的URL

      HttpGethtg0=new HttpGet(uri);

接下来我们再看我们想要的数据是怎么来的。

很明显是通过一系列的post方法从服务器的response中以json的形式返回的。其中flowfee就是费用,totalflow时长。


这里有一个问题难住了很久,百度了好久最后才实验出来一个解决方法,那就是我直接模拟这个post包向服务器的地址post数据并没有获得想要的返回,而是提示500错误,最后的解决办法是这样的。从上图可以看到我们psot过去的还有很多不明意义的东西,我点开都看了看完全不知道是干嘛的,但是事实就是我们把前面那几条不明意义的数据向服务器post过去后就可以正常返回我们想要的数据了。至于应该怎么解析json之类的小问题百度一下就好啦。

在本文最后会附上电脑的Java源码,记得要导入几个jar包才可以运行。

接下来就是神一般的三天安卓速成大法了,我在网上找了几本Android开发教程,从目录里找我需要用到的章节,只学需要用到的地方,所以才能只用了三天就写出来这个安卓程序。实际上也很简单,只有一个Activity,布局上直接拖得控件也没做什么设计。真正的难点是多线程的使用。因为在Android中需要处理网络任务的时候不能再主线程中处理,主线程只能进行UI的处理。所以在如何使用handler这方面百度了很多很多例子,最终成功的实现了多线程的编写。除了最主要的抓取数据的程序外,剩下就是一些记住密码啊,从系统中读取当前日期之类的小地方的细节,最终写出来了这个APP并且先给同学试用了一下,最终上传到百度云通过贴吧和空间稍微推广一下希望能够帮到更多的同学。

其实做完之后自己的感想就是,现在网络上资源十分丰富,也有各种前辈写的各种blog能够给你提供详细的讲解和实例,你真正需要挑战的是自己的耐性。能不能够静下心来决心去做好这件事,然后在试错的道路上坚持下来一直走到你最终找到了正确的道路的那一刻。

我一开始不知道httpclient,试图自己处理COOKIEs,下载安卓的开发软件和环境也是个挑战,后来Android开发的时候导入jar包也出了很多问题(最后用的本身SDK带的org.apache包),调试的时候不知道断点怎么用的,多线程试图模仿着写了3个都没能用,还有好多乱七八糟的问题,但是现在都想不起来了,只是记得当时自己哪怕很烦,哪怕半夜断网我开着流量下sdk,我都没有放弃,可能总共花了5,60个小时做这个事,其中估摸着除了十个小时是在做正确的事,其他时候都是在做无用功,但是我还是做出来了。

这是我上大学以来做出的最有成就感的事情了,完全独立的解决(好吧,Android调试我问了问做过开发的同学)一个问题,真的很有成就感。这个算是教程也算是心得的东西早就想写了,但是自己又犯了拖延症一直到放假都没有写出来。现在发出来望各位大学迷茫的it狗们共勉。

附:

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
importorg.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import net.sf.json.JSONObject;
public class HelloWorld {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
CloseableHttpClienthttpclient = HttpClients.createDefault();

/**
*登陆
*生成uri用get方法传递过去即可
*/
URIuri=new URIBuilder()
.setScheme("https")
.setHost("uac.10010.com")
.setPath("/portal/Service/MallLogin")
.setParameter("callback","jQuery17204165900954174946_1450622603532")
.setParameter("redirectURL","http%3A%2F%2Fwww.10010.com")
.setParameter("userName","051602198839")//用户名
.setParameter("password","xxxxxx")//密码
.setParameter("pwdType","01")
.setParameter("productType","04")
.setParameter("redirectType","01")
.setParameter("areaCode","350")
.setParameter("arrcity","%E5%BE%90%E5%B7%9E")
.setParameter("_","1450622609168")
.build();//生成想要的URL
HttpGethtg0=new HttpGet(uri);
HttpResponseresponse0 = httpclient.execute(htg0);
System.out.println(htg0.getURI());
System.out.println(response0.getStatusLine());
StringcOnfirm= EntityUtils.toString(response0.getEntity(),"utf-8");
if (confirm.contains("resultCode:\"0000\""))
System.out.println("登陆成功");
/*
* 依次向服务器post
* 前面这些貌似必须先请求响应,会自动生成COOKIE
* 均为不带post实体内容的
*/
HttpPostpostU=new HttpPost();
ListpostUri=new ArrayList<>();
postUri.add("http://iservice.10010.com/e3/static/check/checklogin/?_=1450697102496");
postUri.add("http://iservice.10010.com/e3/static/common/info?_=1450697103996");
postUri.add("http://iservice.10010.com/e3/static/header");
postUri.add("http://iservice.10010.com/e3/static/query/newsAssistant/search?_=1450697104007");
postUri.add("http://iservice.10010.com/e3/static/check/checklogin?_=1450697104017");
postUri.add("http://iservice.10010.com/e3/static/check/checklogin?_=1450697104361");
for(Stringpost:postUri)
{
URIpoU=new URIBuilder(post).build();
postU.setURI(poU);
response0=httpclient.execute(postU);
System.out.println(response0.getStatusLine());
System.out.println("执行完成");
Stringresult0=EntityUtils.toString(response0.getEntity(),"utf-8");
System.out.println(result0);
}
System.out.println("准备完成");
/*
* 最后post能够得到想要数据的那条
*/
HttpPosthtp=new HttpPost("http://iservice.10010.com/e3/static/query/callFlow?_=1450697104585&menuid=000100030004");
Listparameters =new ArrayList();
//请求体
parameters.add(new BasicNameValuePair("pageNo","1"));
parameters.add(new BasicNameValuePair("pageSize","20"));
parameters.add(new BasicNameValuePair("beginDate","2015-12-01"));//
parameters.add(new BasicNameValuePair("endDate","2015-12-25"));
UrlEncodedFormEntity urlEntity = newUrlEncodedFormEntity(parameters,"UTF-8");
htp.setEntity(urlEntity);

CloseableHttpResponseresponse1 =httpclient.execute(htp);
System.out.println(response1.getStatusLine());
String result = EntityUtils.toString(response1.getEntity(),"utf-8");
System.out.println(result);
JSONObject ob = JSONObject.fromObject(result);
String totalflow=ob.get("totalflow").toString();
System.out.println(totalflow);

}
}


  

 

附2(Android源码):
 
 
package com.example.sunyang.myapplication;import android.content.SharedPreferences;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import org.json.JSONArray;import org.json.JSONObject;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.MulticastSocket;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;public class MainActivity extends AppCompatActivity {    TextView res;    HttpClient httpClient;    SharedPreferences preferences;    SharedPreferences.Editor editor;    /*    主线程中构造handler,更新UI的请求用sendMessage发送,在下面完成.     */    Handler handler=new Handler(){        public void handleMessage(Message msg){            if (msg.what==0x123){                res.append(msg.obj.toString()+"\n");            }        }    };    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        httpClient=new DefaultHttpClient();        preferences=getSharedPreferences("userInfo",MODE_WORLD_READABLE);        editor=preferences.edit();        res=(TextView) findViewById(R.id.result);        Button bn=(Button) findViewById(R.id.button);        final EditText username=(EditText) findViewById(R.id.userName);        final EditText password=(EditText) findViewById(R.id.password);        final CheckBox checkBox=(CheckBox) findViewById(R.id.checkBox);        if (preferences.getBoolean("AUTO_ISCHECK",true)){            username.setText(preferences.getString("userName", ""));            password.setText(preferences.getString("password", ""));        }        bn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                final String name=username.getText().toString();                final String pwd=password.getText().toString();                if(checkBox.isChecked()){                    editor.putString("userName", name);                    editor.putString("password", pwd);                    editor.putBoolean("AUTO_ISCHECK", true).commit();//存储用户名密码在xml文件                }                else editor.putBoolean("AUTO_ISCHECK",false).commit();                new Thread()                {                    /*                    用于网络的线程                     */                    public void run(){                        try{                            /*                            用于登陆的代码                             */                            String url="https://uac.10010.com/portal/Service/MallLogin?callback=jQuery17204165900954174946_1450622603532&redirectURL=http%253A%252F%252Fwww.10010.com" +                                    "&userName=" +name+                                    "&password=" +pwd+                                    "&pwdType=01&productType=04&redirectType=01&areaCode=350&arrcity=%25E5%25BE%2590%25E5%25B7%259E&_=1450622609168";                            HttpGet get=new HttpGet(url);                            HttpResponse respOnse=httpClient.execute(get);                            String cOnfirm= EntityUtils.toString(response.getEntity(), "utf-8");                            Message msg = new Message();                            msg.what=0x123;                            if (confirm.contains("resultCode:\"0000\"")){                                msg.obj="登陆成功";                                handler.sendMessage(msg);                            }                            else {                                msg.obj="用户名或者密码错误";                                handler.sendMessage(msg);                            }                            /*                            发送post请求的代码                             */                            List postUri=new ArrayList<>();                            postUri.add("http://iservice.10010.com/e3/static/check/checklogin/?_=1450697102496");                            postUri.add("http://iservice.10010.com/e3/static/common/info?_=1450697103996");                            postUri.add("http://iservice.10010.com/e3/static/header");                            postUri.add("http://iservice.10010.com/e3/static/query/newsAssistant/search?_=1450697104007");                            postUri.add("http://iservice.10010.com/e3/static/check/checklogin?_=1450697104017");                            postUri.add("http://iservice.10010.com/e3/static/check/checklogin?_=1450697104361");                            for(String post:postUri)                            {                                HttpPost postU=new HttpPost(post);                                HttpResponse response0=httpClient.execute(postU);                            }                            Message msg1=new Message();                            msg1.what=0x123;                            msg1.obj="发送请求";                            handler.sendMessage(msg1);                            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");                            SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM");                            String endDate=sdf.format(new Date());                            String beginDate=sdf1.format(new Date())+"-01";                            Message msg2=new Message();                            msg2.what=0x123;                            msg2.obj="开始日期:"+beginDate+"\t截止日期:"+endDate;                            handler.sendMessage(msg2);                            HttpPost htp=new HttpPost("http://iservice.10010.com/e3/static/query/callFlow?_=1450697104585&menuid=000100030004");                            List parameters = new ArrayList();                            //请求体                            parameters.add(new BasicNameValuePair("pageNo", "1"));                            parameters.add(new BasicNameValuePair("pageSize", "20"));                            parameters.add(new BasicNameValuePair("beginDate", beginDate));                            parameters.add(new BasicNameValuePair("endDate", endDate));                            UrlEncodedFormEntity urlEntity =  new UrlEncodedFormEntity(parameters, "UTF-8");                            htp.setEntity(urlEntity);                            HttpResponse result=httpClient.execute(htp);                            String s = EntityUtils.toString(result.getEntity(), "utf-8");                            //处理结果                            JSONObject ob = new JSONObject(s);                            String totalflow=ob.get("totalflow").toString();                            String fee=ob.get("flowfee").toString();                            int total=Integer.parseInt(totalflow)/3600;                            Message msg3=new Message();                            msg3.what=0x123;                            msg3.obj="时长合计:"+totalflow+"秒\n"+"大约为"+total+"小时\n"+"费用合计:"+fee;                            handler.sendMessage(msg3);                        }                        catch (Exception e){                            e.printStackTrace();                        }                    }                }.start();            }        });    }}


 


推荐阅读
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • Jboss的EJB部署描述符standardjaws.xml配置步骤详解
    本文详细介绍了Jboss的EJB部署描述符standardjaws.xml的配置步骤,包括映射CMP实体EJB、数据源连接池的获取以及数据库配置等内容。 ... [详细]
  • 本文总结了初学者在使用dubbo设计架构过程中遇到的问题,并提供了相应的解决方法。问题包括传输字节流限制、分布式事务、序列化、多点部署、zk端口冲突、服务失败请求3次机制以及启动时检查。通过解决这些问题,初学者能够更好地理解和应用dubbo设计架构。 ... [详细]
author-avatar
颂春堂中药
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有