").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
5 |
--------------------------------------------------------------------------------
/HelloJetty/assets/jetty/static.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Static Resource
5 |
6 |
7 |
8 |
Static Resource
9 |
Jetty on Android, Static Resources copy from assets.
10 |

11 |
12 |
13 |
--------------------------------------------------------------------------------
/HelloJetty/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/ic_launcher-web.png
--------------------------------------------------------------------------------
/HelloJetty/libs/jetty-8.1.15.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/libs/jetty-8.1.15.jar
--------------------------------------------------------------------------------
/HelloJetty/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/HelloJetty/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/HelloJetty/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloJetty/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloJetty/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloJetty/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youten/JettyOnAndroid/3f203f12b9fb1ba62363dc7d46ade31d39f526c9/HelloJetty/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloJetty/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/HelloJetty/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/HelloJetty/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/HelloJetty/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | HelloJetty
4 | Start
5 | Stop
6 | Settings
7 |
8 | Hello world!
9 |
--------------------------------------------------------------------------------
/HelloJetty/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/hello/MainActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.hello;
3 |
4 | import youten.redo.jetty.server.JServer;
5 | import android.os.Bundle;
6 | import android.app.Activity;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 |
10 | public class MainActivity extends Activity {
11 | JServer mServer = new JServer(8081);
12 | MenuItem mStopMenuItem;
13 | MenuItem mStartMenuItem;
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 | }
20 |
21 | @Override
22 | public boolean onCreateOptionsMenu(Menu menu) {
23 | getMenuInflater().inflate(R.menu.main, menu);
24 | mStartMenuItem = menu.findItem(R.id.action_start);
25 | mStopMenuItem = menu.findItem(R.id.action_stop);
26 | setStartMenuEnabled(true);
27 | return true;
28 | }
29 |
30 | @Override
31 | public boolean onOptionsItemSelected(MenuItem item) {
32 | if (item.getItemId() == R.id.action_start) {
33 | mServer.start(getApplicationContext());
34 | setStartMenuEnabled(false);
35 | return true;
36 | } else if (item.getItemId() == R.id.action_stop) {
37 | mServer.stop();
38 | setStartMenuEnabled(true);
39 | return true;
40 | }
41 | return super.onOptionsItemSelected(item);
42 | }
43 |
44 | @Override
45 | protected void onDestroy() {
46 | super.onDestroy();
47 | mServer.stop();
48 | }
49 |
50 | private void setStartMenuEnabled(boolean startMenuEnabled) {
51 | mStartMenuItem.setEnabled(startMenuEnabled);
52 | mStopMenuItem.setEnabled(!startMenuEnabled);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/http/ContentType.java:
--------------------------------------------------------------------------------
1 | package youten.redo.jetty.http;
2 |
3 | public class ContentType {
4 | /** Content-Type: text/html */
5 | public static final String HTML = "text/html";
6 | }
7 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/ChatRoom.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import java.io.IOException;
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 | import java.util.Locale;
8 | import java.util.Map;
9 | import java.util.concurrent.ConcurrentHashMap;
10 |
11 | import android.util.Log;
12 |
13 | public class ChatRoom {
14 | private static final String TAG = "ChatRoom";
15 | private int mIdCounter = 0;
16 | private Map
mUsers = new ConcurrentHashMap();
17 |
18 | // WebSocketコネクションを登録する
19 | // ついでに適当なIDを割り当てる
20 | public void join(ChatWebSocket ws) {
21 | if (mUsers.containsKey(ws)) {
22 | return;
23 | }
24 | mIdCounter++;
25 | mUsers.put(ws, mIdCounter);
26 | sendAll("login " + mIdCounter);
27 | Log.d(TAG, "login " + mIdCounter);
28 | }
29 |
30 | // 登録されていたコネクションを取り除く
31 | public void leave(ChatWebSocket ws) {
32 | int id = mUsers.get(ws);
33 | mUsers.remove(ws);
34 | sendAll("logoff " + id);
35 | Log.d(TAG, "logoff " + id);
36 | }
37 |
38 | // WebSocketからメッセージが届いたら付加情報を付けて全コネクションに流す
39 | public void onMessage(ChatWebSocket ws, String msg) {
40 | int id = mUsers.get(ws);
41 | SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
42 | msg = id + ": " + msg + " " + fmt.format(new Date());
43 | sendAll(msg);
44 | Log.d(TAG, msg);
45 | }
46 |
47 | // 抱えてる全コネクションに流す
48 | public void sendAll(String msg) {
49 | for (ChatWebSocket socket : mUsers.keySet()) {
50 | try {
51 | socket.send(msg);
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/ChatWebSocket.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import java.io.IOException;
5 |
6 | import org.eclipse.jetty.websocket.WebSocket;
7 |
8 | public class ChatWebSocket implements WebSocket.OnTextMessage {
9 | private Connection mConnection;
10 | private ChatRoom mChatRoom;
11 |
12 | public ChatWebSocket(ChatRoom chatroom) {
13 | if (chatroom == null) {
14 | throw new IllegalArgumentException();
15 | }
16 |
17 | mChatRoom = chatroom;
18 | }
19 |
20 | // WebSocket が繋がったら chatroom に join する
21 | @Override
22 | public void onOpen(Connection conn) {
23 | mConnection = conn;
24 | mChatRoom.join(this);
25 | }
26 |
27 | // WebSocket が切れたら chatroom から leave する
28 | @Override
29 | public void onClose(int closeCode, String msg) {
30 | mChatRoom.leave(this);
31 | }
32 |
33 | // メッセージが飛んできたら chatroom にお任せする
34 | @Override
35 | public void onMessage(String msg) {
36 | mChatRoom.onMessage(this, msg);
37 | }
38 |
39 | // この接続先にメッセージを投げる
40 | public void send(String msg) throws IOException {
41 | mConnection.sendMessage(msg);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/HelloServlet.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import java.io.IOException;
5 |
6 | import javax.servlet.ServletException;
7 | import javax.servlet.http.HttpServlet;
8 | import javax.servlet.http.HttpServletRequest;
9 | import javax.servlet.http.HttpServletResponse;
10 |
11 | /**
12 | * Hello Servlet
13 | */
14 | public class HelloServlet extends HttpServlet {
15 | private static final long serialVersionUID = 1L;
16 |
17 | @Override
18 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
19 | IOException {
20 | ServletUtil.responseHtml(resp, "Hello, Jetty", "Hello, Jetty Servlet!");
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/JServer.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 |
11 | import org.eclipse.jetty.server.Server;
12 | import org.eclipse.jetty.server.handler.HandlerList;
13 | import org.eclipse.jetty.server.handler.ResourceHandler;
14 | import org.eclipse.jetty.servlet.ServletContextHandler;
15 | import org.eclipse.jetty.servlet.ServletHolder;
16 |
17 | import android.content.Context;
18 | import android.content.res.AssetManager;
19 | import android.os.Environment;
20 |
21 | /**
22 | * Jetty Server
23 | */
24 | public class JServer {
25 | private static final String TAG = "JServer";
26 | private static final String ASSETS_DIR = "jetty";
27 | private int mPort;
28 | private Server mServer;
29 |
30 | /**
31 | * コンストラクタ
32 | *
33 | * @param port Jettyを起動するport
34 | */
35 | public JServer(int port) {
36 | mPort = port;
37 | }
38 |
39 | /**
40 | * Serverを開始する。
41 | */
42 | public synchronized void start(Context applicationContext) {
43 | if ((mServer != null) && (mServer.isStarted())) {
44 | return;
45 | }
46 | if (mServer == null) {
47 | // setup Servlet Handler
48 | ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
49 | // Hello Servletを "/hello"に割り当て
50 | servletHandler.addServlet(new ServletHolder(new HelloServlet()), "/hello");
51 | // WebSocketなChat Servletを"/wschat"に割り当て
52 | servletHandler.addServlet(new ServletHolder(new WSChatServlet()), "/wschat");
53 |
54 | // setup Resource Handler
55 | // assets配下を展開
56 | extractAssets(applicationContext.getResources().getAssets(), ASSETS_DIR);
57 | String resourceBase = Environment.getExternalStorageDirectory().getAbsolutePath()
58 | + "/" + ASSETS_DIR;
59 | // 静的リソースルート"(外部ストレージ)/jetty"に設定
60 | ResourceHandler resourceHandler = new ResourceHandler();
61 | resourceHandler.setResourceBase(resourceBase);
62 |
63 | // setup Server and Handler List
64 | HandlerList handlerList = new HandlerList();
65 | handlerList.addHandler(servletHandler);
66 | handlerList.addHandler(resourceHandler);
67 | mServer = new Server(mPort);
68 | mServer.setHandler(handlerList);
69 | }
70 |
71 | try {
72 | mServer.start();
73 | } catch (Exception e) {
74 | e.printStackTrace();
75 | }
76 | }
77 |
78 | // 参考:http://d.hatena.ne.jp/corrupt/20110203/1296695472
79 | private static void extractAssets(final AssetManager am, final String assetsDir) {
80 | // 配下のファイルリストを取得
81 | String[] files = null;
82 | try {
83 | if (am != null) {
84 | files = am.list(assetsDir);
85 | }
86 | } catch (IOException e) {
87 | e.printStackTrace();
88 | }
89 | if ((files == null) || (files.length == 0)) {
90 | return;
91 | }
92 |
93 | // extract
94 | File extractDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
95 | + "/" + assetsDir);
96 | if (extractDir.isFile()) {
97 | extractDir.delete(); // Fileとしてゴミが残っていたら消してみる。
98 | return;
99 | }
100 | if (!extractDir.exists()) {
101 | extractDir.mkdirs();
102 | }
103 |
104 | for (String file : files) {
105 | InputStream in = null;
106 | BufferedOutputStream out = null;
107 | try {
108 | in = am.open(assetsDir + "/" + file);
109 | out = new BufferedOutputStream(new FileOutputStream(new File(
110 | extractDir, file)));
111 | byte[] buffer = new byte[4 * 1024]; // 4k
112 | int len = 0;
113 | while ((len = in.read(buffer)) != -1) {
114 | out.write(buffer, 0, len);
115 | }
116 | out.close();
117 | in.close();
118 | } catch (FileNotFoundException e) {
119 | // FileNotFoundの際にはdirectoryと見なす
120 | extractAssets(am, assetsDir + "/" + file);
121 | continue;
122 | } catch (IOException e) {
123 | e.printStackTrace();
124 | continue;
125 | } finally {
126 | try {
127 | if (out != null) {
128 | out.close();
129 | }
130 | if (in != null) {
131 | in.close();
132 | }
133 | } catch (IOException e) {
134 | // ignore
135 | }
136 | }
137 |
138 | }
139 |
140 | }
141 |
142 | /**
143 | * Serverを停止する。
144 | */
145 | public synchronized void stop() {
146 | if ((mServer == null) || (mServer.isStopped())) {
147 | return;
148 | }
149 | try {
150 | mServer.stop();
151 | } catch (Exception e) {
152 | e.printStackTrace();
153 | }
154 | }
155 |
156 | /**
157 | * Serverが起動しているかどうか
158 | *
159 | * @return 起動していたらtrueを、それ以外はfalseを返す。
160 | */
161 | public synchronized boolean isStarted() {
162 | if (mServer == null) {
163 | return false;
164 | }
165 | return mServer.isStarted();
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/ServletUtil.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import java.io.IOException;
5 |
6 | import javax.servlet.http.HttpServletResponse;
7 |
8 | import org.apache.http.protocol.HTTP;
9 |
10 | import youten.redo.jetty.http.ContentType;
11 |
12 | public class ServletUtil {
13 | public static final String LS = System.getProperty("line.separator");
14 |
15 | /**
16 | * 単純なHtmlを返す。
17 | * @param resp
18 | * @param title
19 | * @param message
20 | * @throws IOException
21 | */
22 | public static void responseHtml(HttpServletResponse resp, String title, String message) throws IOException {
23 | resp.setCharacterEncoding(HTTP.UTF_8);
24 | resp.setContentType(ContentType.HTML);
25 | StringBuilder sb = new StringBuilder();
26 | sb.append("").append(LS);
27 | sb.append("").append(title).append("").append(LS);
28 | sb.append("").append(title).append("
").append(LS);
29 | sb.append("").append(message).append("
").append(LS);
30 | sb.append("").append(LS);
31 |
32 | resp.getWriter().println(sb.toString());
33 | }
34 |
35 | private ServletUtil() {
36 | // Util
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/HelloJetty/src/youten/redo/jetty/server/WSChatServlet.java:
--------------------------------------------------------------------------------
1 |
2 | package youten.redo.jetty.server;
3 |
4 | import javax.servlet.http.HttpServletRequest;
5 |
6 | import org.eclipse.jetty.websocket.WebSocket;
7 | import org.eclipse.jetty.websocket.WebSocketServlet;
8 |
9 | public class WSChatServlet extends WebSocketServlet {
10 | private static final long serialVersionUID = 1L;
11 | ChatRoom mChatRoom = new ChatRoom();
12 |
13 | @Override
14 | public WebSocket doWebSocketConnect(HttpServletRequest req, String protocol) {
15 | return new ChatWebSocket(mChatRoom);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | JettyOnAndroid
2 | ====
3 | Jetty on Android.
4 |
5 | ## Projects
6 |
7 | HelloJetty - Jetty on Android Sample, using WebSocket.
8 |
9 | ## How re-archive jetty-x.x.x.jar
10 | - download binary tarball from http://download.eclipse.org/jetty/
11 | - extract
12 |
13 | ```bash
14 | tar xvf jetty-distribution-8.1.15.v20140411.tar.gz
15 | cd jetty-distribution-8.1.15.v20140411/lib/ext/
16 | ```
17 |
18 | - re-archive
19 |
20 | ```bash
21 | cd jetty-distribution-8.1.15.v20140411/lib/ext/
22 | jar xf ../jetty-continuation-*.jar
23 | jar xf ../jetty-http-*.jar
24 | jar xf ../jetty-io-*.jar
25 | jar xf ../jetty-security-*.jar
26 | jar xf ../jetty-server-*.jar
27 | jar xf ../jetty-servlet-*.jar
28 | jar xf ../jetty-util-*.jar
29 | jar xf ../jetty-webapp-*.jar
30 | jar xf ../jetty-websocket-*.jar
31 | jar xf ../jetty-xml-*.jar
32 | jar xf ../servlet-api-*.jar
33 | rm -rf about*
34 | jar cf ../jetty-8.1.15.jar *
35 | cd ..
36 | ```
37 |
38 | - copy jetty-x.x.x.jar to Android's Project libs/ folder.
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------