從零開始學會做一個簡單的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();
      List<String>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(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");
      List<NameValuePair>parameters =new ArrayList<NameValuePair>();
      //請求體
       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<String> 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<NameValuePair> parameters = new ArrayList<NameValuePair>();
                            //請求體
                            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();
            }
        });
    }
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章