原生Android也能做Web開(kāi)發(fā)了

轉(zhuǎn)自嚴(yán)振杰的博客:http://blog.yanzhenjie.com

Features Image
Features Image

大家好,今天跟大家介紹一個(gè)讓原生Android也可以做Web開(kāi)發(fā)的開(kāi)源項(xiàng)目——AndServer点晴。
開(kāi)源地址:https://github.com/yanzhenjie/AndServer

AndServer

是一個(gè)Android端的Web服務(wù)器选侨,類(lèi)似Apache或者Tomcat完沪,但又有不同戏罢,它是一個(gè)普通的Android Library烁兰,Android項(xiàng)目Gradle遠(yuǎn)程依賴(lài)或者添加Jar包皆可引入該項(xiàng)目减响,然后就通過(guò)正常Android開(kāi)發(fā)一樣開(kāi)發(fā)App了靖诗。

AndServer

是用純Android API寫(xiě)一個(gè)庫(kù),所以不用任何第三方的庫(kù)或者什么硬件編譯支示,打成Jar包后僅僅580kb刊橘。
很多人看到這里就有疑問(wèn)了:**它的使用場(chǎng)景是什么?
**按照國(guó)際慣例颂鸿,我舉個(gè)栗子:
某公司公開(kāi)了一款TV APP促绵,可以安裝在電視或者盒子上,有一個(gè)功能是這樣的: APP安裝在電視上打開(kāi)后据途,會(huì)生成一個(gè)唯一ID绞愚,用戶用微信掃碼通過(guò)公司提供的公眾號(hào)和該電視上的該APP綁定,用戶通過(guò)公眾號(hào)打開(kāi)一個(gè)H5頁(yè)面颖医,這個(gè)頁(yè)面可以上傳圖片或者視頻到服務(wù)器位衩,服務(wù)器檢測(cè)到該用戶和某個(gè)屏幕的APP綁定,動(dòng)態(tài)把用戶發(fā)送的圖片或者視頻發(fā)送到電視播放熔萧。 這樣一個(gè)功能是很好的體驗(yàn)糖驴,但是耗費(fèi)服務(wù)器資源、遠(yuǎn)端上傳佛致、遠(yuǎn)端下載也都需要時(shí)間贮缕,還不如我直接用U盤(pán)拷貝到電視呢。那么如果我通過(guò)網(wǎng)頁(yè)在局域網(wǎng)直接把視頻或者圖片發(fā)送到電視上的APP播放俺榆,豈不是更加直接快捷感昼?

當(dāng)然大部分同學(xué)可能很少接觸到APP之間互相在局域網(wǎng)通信、局域網(wǎng)上傳下載罐脊、局域網(wǎng)登錄這樣的需求定嗓,還有很多栗子我就不舉了,下面開(kāi)始正式安利萍桌。

特點(diǎn)

接受客戶端文件上傳宵溅、下載文件。
動(dòng)態(tài)Http API上炎,就像Java的Servlet一樣寫(xiě)接口恃逻。
部署靜態(tài)網(wǎng)站,例如純Html,支持JS寇损、CSS凸郑、Image分離。
部署動(dòng)態(tài)網(wǎng)站润绵,例如Html表單线椰,當(dāng)然可以結(jié)合上面的Android Http接口。

基本上和Java的Servlet一樣的功能尘盼,如果你做過(guò)Java開(kāi)發(fā)或者其它語(yǔ)言的Web開(kāi)發(fā)應(yīng)該就很熟悉了。

依賴(lài)

Gradle

compile 'com.yanzhenjie:andserver:1.0.2'

Maven

<dependency>
  <groupId>com.yanzhenjie</groupId>
  <artifactId>andserver</artifactId>
  <version>1.0.2</version>
  <type>pom</type>
</dependency>

ADT烦绳,可以去AndServer主頁(yè)下載Jar包卿捎。

使用方法

最好的教程是sample,建議到AndServer主頁(yè)下載sample運(yùn)行查看效果径密,然后結(jié)合README就更加清晰了午阵。

創(chuàng)建服務(wù)器
AndServer andServer = new AndServer.Build()
    ...
    .build();

// 創(chuàng)建服務(wù)器。
Server mServer = andServer.createServer();
...

// 啟動(dòng)服務(wù)器享扔。
mServer.start();
...

// 停止服務(wù)器底桂。
mServer.stop();
...

// 服務(wù)器正在運(yùn)行嗎?
boolean running = mServer.isRunning();
端口號(hào)和響應(yīng)超時(shí)設(shè)置
AndServer andServer = new AndServer.Build()
    .port(8080) // 默認(rèn)是8080惧眠,Android平臺(tái)允許的端口號(hào)都可以籽懦。
    .timeout(10 * 1000) // 默認(rèn)10 * 1000毫秒。
    ...
    .build();
...
部署網(wǎng)站

部署網(wǎng)站是通過(guò)Website接口氛魁,你也可以自己實(shí)現(xiàn)這個(gè)接口暮顺,當(dāng)然AndServer
已經(jīng)提供了兩個(gè)默認(rèn)實(shí)現(xiàn):
AssetsWebsite
StorageWebsite

如果用上面兩個(gè)實(shí)現(xiàn)注冊(cè)你的網(wǎng)站,那么你的默認(rèn)首頁(yè)(index.html)是:

http://ip:port/
http://ip:port/youPath
http://ip:port/youPath/index.html

注冊(cè)網(wǎng)站到AndServer

// 或者
Wesite wesite = new StorageWebsite(youPath);

AndServer andServer = new AndServer.Build()
    ...
    .website(wesite);
    .build();

AssetsWebsite的使用

如果你的網(wǎng)站在assets下秀存,那么你就用AssetsWebsite來(lái)部署你的網(wǎng)站捶码。使用方法是:

//AssetManager不能被關(guān)閉。
AssetManager mAssetManager = getAssets();

Wesite wesite = new AssetsWebsite(mAssetManager, youPath);

上面我們看到new AssetsWebsite時(shí)需要傳一個(gè)AssetManager和一個(gè)path或链,path支持assets根目錄和子目錄惫恼,下面是這兩種情況的舉例。如果你的網(wǎng)站在assets根目錄下, 你的path就填""澳盐,比如:

Assets根目錄
Assets根目錄
Wesite wesite = new AssetsWebsite(mAssetManager, "");

那么你的默認(rèn)首頁(yè)訪問(wèn)地址就是:

http://ip:porthttp://ip:port/index.html

那么你的其它頁(yè)面訪問(wèn)地址是:

http://ip:port/login.htmlhttp://ip:port/error.html

比如:

http://192.168.1.12:8080/index.html 
http://192.168.1.12:8080/login.html
```

如果你的網(wǎng)站根目錄在assets的子目錄下祈纯,那么你傳入assets的相對(duì)目錄地址就好了比如你的網(wǎng)站在assets下web目錄,例如:

![Assets子目錄](méi)(https://dn-mhke0kuv.qbox.me/bd0a4a7041e8e8e5e35c.png)
```
Wesite wesite = new AssetsWebsite(mAssetManager, "web");
```
那么你的默認(rèn)首頁(yè)訪問(wèn)地址就是:
```
http://ip:porthttp://ip:port/webhttp://ip:port/web/index.html
```
那么你的其它頁(yè)面訪問(wèn)地址是:
```
http://ip:port/web/login.html http://ip:port/web/error.html
```

例如:
```
http://192.168.1.12:8080/
http://192.168.1.12:8080/index.html
http://192.168.1.12:8080/web/index.html
http://192.168.1.12:8080/web/index.html  
http://192.168.1.12:8080/web/login.html
```

###StorageWebsite的使用
如果你的網(wǎng)站在內(nèi)存設(shè)備下洞就,只要以文件的形式可以讀取到盆繁,那么你就用StorageWebsite來(lái)部署你的網(wǎng)站,比如你的網(wǎng)站在SD卡下時(shí)旬蟋。使用方法是:
```
Wesite wesite = new StorageWebsite(youPath);
```
它很簡(jiǎn)單油昂,只要傳入你的網(wǎng)站的存儲(chǔ)目錄地址即可,例如你的網(wǎng)站在SD卡下的www目錄:
```
File file = new File(Environment.getExternalStorageDirectory(), "www");
String websiteDirectory = file.getAbsolutePath();
Wesite wesite = new StorageWebsite(websiteDirectory);
```


訪問(wèn)地址和AssetsWebsite的道理相同。
###像Servlet一樣寫(xiě)Http接口
Http API是通過(guò)RequestHandler接口來(lái)注冊(cè)的冕碟,它是一個(gè)[Java ](http://lib.csdn.net/base/java)interface拦惋,它和Java的Servlet一樣。你需要實(shí)現(xiàn)這個(gè)接口安寺,然后在AndServer注冊(cè)即可厕妖,
例如:
```
public class RequestLoginHandler implements RequestHandler {

    @Override
    public void handle(HttpRequest req, HttpResponse res, HttpContext con) {
        Map<String, String> params = HttpRequestParser.parse(request);

        // Request params.        
        String userName = params.get("username");
        String password = params.get("password");

        if ("123".equals(userName) && "123".equals(password)) {
            StringEntity stringEntity = new StringEntity("Login Succeed", "utf-8");
            response.setEntity(stringEntity);
        } else {
            StringEntity stringEntity = new StringEntity("Login Failed", "utf-8");
            response.setEntity(stringEntity);
        }
    }
}
```
然后在AndServer中注冊(cè):
```
AndServer andServer = new AndServer.Build()
    ...
    .registerHandler("login", new RequestLoginHandler())
    .build();
```

現(xiàn)在你就得到了一個(gè)唯一的訪問(wèn)地址:http://ip:port/login, 例如:
```
http://192.168.1.12:8080/login?username=123&password=123
```
文件下載和文件上傳的例子請(qǐng)下載sample查看。提交Html表單到Android端在Html的form的action中填入你注冊(cè)RequestHandler時(shí)的key就可以了挑庶,然后在RequestHandler的
```
handle(HttpRequest, HttpResponse, HttpContext)
```

方法就可以獲取form提交的參數(shù)了言秸。比如我們上面注冊(cè)Login RequestHandler在form中這樣使用:
```
<form id="form1" method="post" action="login">
...
</form>
```

###監(jiān)聽(tīng)服務(wù)器的狀態(tài)
服務(wù)器一般情況下有三種狀態(tài):成功啟動(dòng)、啟動(dòng)時(shí)失敗迎捺、成功停止服務(wù)器举畸,失敗時(shí)會(huì)返回一個(gè)異常,一般情況下是網(wǎng)絡(luò)問(wèn)題或者端口被占用
```
private Server.Listener mListener = new Server.Listener() {
    @Override
    public void onStarted() {
        // 服務(wù)器啟動(dòng)成功.
    }

    @Override
    public void onStopped() {
        // 服務(wù)器停止了凳枝,一般是開(kāi)發(fā)者調(diào)用server.stop()才會(huì)停止抄沮。
    }

    @Override
    public void onError(Exception e) {
        // 服務(wù)器啟動(dòng)發(fā)生錯(cuò)誤,一般是端口被占用岖瑰。
    }
};

AndServer andServer = new AndServer.Build()
    ...
    .listener(mListener)
    .build();
```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叛买,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蹋订,更是在濱河造成了極大的恐慌,老刑警劉巖辅辩,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件难礼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡玫锋,警方通過(guò)查閱死者的電腦和手機(jī)蛾茉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撩鹿,“玉大人谦炬,你說(shuō)我怎么就攤上這事〗诼伲” “怎么了键思?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)甫贯。 經(jīng)常有香客問(wèn)我吼鳞,道長(zhǎng),這世上最難降的妖魔是什么叫搁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任赔桌,我火速辦了婚禮供炎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疾党。我一直安慰自己音诫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布雪位。 她就那樣靜靜地躺著竭钝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雹洗。 梳的紋絲不亂的頭發(fā)上香罐,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音时肿,去河邊找鬼穴吹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗜侮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啥容,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼锈颗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了咪惠?” 一聲冷哼從身側(cè)響起击吱,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遥昧,沒(méi)想到半個(gè)月后覆醇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炭臭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年永脓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鞋仍。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冕茅,到底是詐尸還是另有隱情析显,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布肚豺,位于F島的核電站溃斋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吸申。R本人自食惡果不足惜梗劫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一享甸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧在跳,春花似錦枪萄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至割坠,卻和暖如春齐帚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背彼哼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工对妄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敢朱。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓剪菱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拴签。 傳聞我的和親對(duì)象是個(gè)殘疾皇子孝常,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,180評(píng)論 25 707
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)蚓哩,斷路器构灸,智...
    卡卡羅2017閱讀 134,665評(píng)論 18 139
  • 生來(lái)就不平等的 不單單只是人 還有萬(wàn)事萬(wàn)物 起初,欲望和理想 我們都分的清 后來(lái)岸梨,自己卻慢慢松懈 只看到眼前的不平...
    達(dá)爾大尼央閱讀 196評(píng)論 0 1
  • 據(jù)說(shuō)一個(gè)人厚著臉皮沒(méi)羞沒(méi)臊地去愛(ài)另一個(gè)人的概率一生只有一次喜颁,你用完了嗎? 有沒(méi)有那么一場(chǎng)夢(mèng)曹阔,你不愿意醒來(lái)半开;有沒(méi)有那...
    左郁閱讀 211評(píng)論 0 0
  • 前言 最近在關(guān)注限流、降級(jí)次兆、監(jiān)控等系統(tǒng)穩(wěn)定性方面的技術(shù)稿茉,反復(fù)牽涉到的幾個(gè)技術(shù)名詞是日志log,Aop切片芥炭。 限流降...
    LNAmp閱讀 1,682評(píng)論 2 4