用浏览器跳转APP研究方案记录

来源:互联网 发布:淘宝查看付款排名 编辑:程序博客网 时间:2024/05/19 00:54

Android实现通过浏览器点击链接打开本地应用(APP)并拿到浏览器传递的数据



Java Socket现实简单的HTTP服务

总结 scema方式部分浏览器有限制,通过监听端口方式或许可以解决



package com.example.jumptest.simpleHttpServer;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.net.URLDecoder;import java.util.ArrayList;import java.util.StringTokenizer;import com.example.jumptest.XActivity;import android.content.Context;import android.content.Intent;import android.os.Handler;import android.os.Message;import android.webkit.WebView.FindListener;import android.widget.Toast;/** *  * @author 参考地址http://blog.csdn.net/a9529lty/article/details/7174259  * modi by jzj * */public class SimpleHttpServer implements Runnable {ServerSocket serverSocket;//服务器Socketpublic static int PORT = 8089;//标准HTTP端口public String encoding = "GBK"; Handler mHandler;public SimpleHttpServer( Handler myHandler) {try {serverSocket = new ServerSocket(PORT);mHandler=myHandler;} catch (Exception e) {e.printStackTrace();System.exit(1);} new Thread(this).start();System.out.println("HTTP服务器正在运行,端口:" + PORT);}public void run() {while (true) {try {Socket client = serverSocket.accept();//客户机(这里是 IE 等浏览器)已经连接到当前服务器if (client != null) {System.out.println("连接到服务器的用户:" + client);try {// 第一阶段: 打开输入流InputStream is = client.getInputStream();System.out.println("客户端发送的请求信息: >>>>>>>>>>>>>>>>>>>>>>>>>");// 读取第一行, 请求地址String line = readLine(is, 0);//打印请求行System.out.print(line);// < Method > < URL > < HTTP Version > <\r\n>  取的是URL部分String resource = line.substring(line.indexOf('/'), line.lastIndexOf('/') - 5);//获得请求的资源的地址resource = URLDecoder.decode(resource, encoding);//反编码 URL 地址?a=996int tvIndex= resource.indexOf("?tv");if(tvIndex != -1){ Message message = new Message();                   message.obj = resource.substring(tvIndex+4);                mHandler.sendMessage(message);}    String method = new StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者 POSTint contentLength = 0;//如果为POST方法,则会有消息体长度// 读取所有浏览器发送过来的请求参数头部信息do {line = readLine(is, 0);//如果有Content-Length消息头时取出if (line.startsWith("Content-Length")) {contentLength = Integer.parseInt(line.split(":")[1].trim());}//打印请求部信息System.out.print(line);//如果遇到了一个单独的回车换行,则表示请求头结束} while (!line.equals("\r\n"));//如果是POST请求,则有请求体if ("POST".equalsIgnoreCase(method)) {//注,这里只是简单的处理表单提交的参数,而对于上传文件这里是不能这样处理的,//因为上传的文件时消息体不只是一行,会有多行消息体System.out.print(readLine(is, contentLength));System.out.println();}System.out.println("客户端发送的请求信息结束 <<<<<<<<<<<<<<<<<<<<<<<<<<");System.out.println("用户请求的资源是:" + resource);System.out.println("请求的类型是: " + method);System.out.println();//如果是下载文件if (resource.startsWith("/download")) {fileDownload("test.txt", client);closeSocket(client);continue;}// GIF 图片就读取一个真实的图片数据并返回给客户端if (resource.endsWith(".gif")) {imgDownload("test.gif", client);closeSocket(client);continue;}// 请求 JPG 格式就报错 404if (resource.endsWith(".jpg")) {PrintWriter out = new PrintWriter(client.getOutputStream(),true);out.println("HTTP/1.0 404 Not found");//返回应答消息,并结束应答out.println();// 根据 HTTP 协议, 空行将结束头信息out.close();closeSocket(client);continue;} else {// 用 writer 对客户端 socket 输出一段 HTML 代码PrintWriter out = new PrintWriter(client.getOutputStream(),true);out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答out.println("Content-Type:text/html;charset=" + encoding);out.println();// 根据 HTTP 协议, 空行将结束头信息out.println("<h1> Hello Http Server</h1>");out.println("你好, 这是一个 Java HTTP 服务器 demo 应用.<br>");out.println("您请求的路径是: " + resource + "<br>");out.println("你请求的页面含有图片:<img src='test.gif'><br>"+ "<a href='test.gif'>手动点击打开test.gif图片文件.</a>");out.println("<br>服务器不支持jpg格式图片,所以显示XX:"+ "<img src='test.jpg'><br><a href='test.jpg'>"+ "手动点击打开test.jpg,会跳转另一页面,并且服务返回为404错误</a><br>");out.println("<form method=post action='/path?qryParm=POST URL查询参数' > POST 表单 "+ "<input name=username value='用户'> "+ "<input name=submit type=submit value=submit></form>");out.println("<form method=get action='/path?qryParm=GET URL查询参数' > GET 表单 "+ "<input name=username value='用户'> "+ "<input name=submit type=submit value=submit></form>");out.println("<form method=post action='/path?qryParm=POST URL查询参数'"+ " enctype='multipart/form-data' >"+ "文件上传  <input type='file' name=file1 ><br>"+ "          "+ "<input type='file' name=file2 ><br>"+ "          "+ "<input name=username value='用户'> "+ "<input name=submit type=submit value=submit></form>");out.println("<a href='/download'>点击此处模拟文件下载</a>");out.close();closeSocket(client);}} catch (Exception e) {System.out.println("HTTP服务器错误:" + e.getLocalizedMessage());}}//System.out.println(client+"连接到HTTP服务器");//如果加入这一句,服务器响应速度会很慢} catch (Exception e) {System.out.println("HTTP服务器错误:" + e.getLocalizedMessage());}}}/* * 这里我们自己模拟读取一行,因为如果使用API中的BufferedReader时,它是读取到一个回车换行后 * 才返回,否则如果没有读取,则一直阻塞,这就导致如果为POST请求时,表单中的元素会以消息体传送, * 这时,消息体最末按标准是没有回车换行的,如果此时还使用BufferedReader来读时,则POST提交 * 时会阻塞。如果是POST提交时我们按照消息体的长度Content-Length来截取消息体,这样就不会阻塞 */private String readLine(InputStream is, int contentLe) throws IOException {ArrayList lineByteList = new ArrayList();byte readByte;int total = 0;if (contentLe != 0) {do {readByte = (byte) is.read();lineByteList.add(Byte.valueOf(readByte));total++;} while (total < contentLe);//消息体读还未读完} else {do {readByte = (byte) is.read();lineByteList.add(Byte.valueOf(readByte));} while (readByte != 10);}byte[] tmpByteArr = new byte[lineByteList.size()];for (int i = 0; i < lineByteList.size(); i++) {tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();}lineByteList.clear();String tmpStr = new String(tmpByteArr, encoding);/* http请求的header中有一个Referer属性,这个属性的意思就是如果当前请求是从别的页面链接过 * 来的,那个属性就是那个页面的url,如果请求的url是直接从浏览器地址栏输入的就没有这个值。得 * 到这个值可以实现很多有用的功能,例如防盗链,记录访问来源以及记住刚才访问的链接等。另外,浏 * 览器发送这个Referer链接时好像固定用UTF-8编码的,所以在GBK下出现乱码,我们在这里纠正一下 */if (tmpStr.startsWith("Referer")) {//如果有Referer头时,使用UTF-8编码tmpStr = new String(tmpByteArr, "UTF-8");}return tmpStr;}/*** 关闭客户端 socket 并打印一条调试信息.* @param socket 客户端 socket.*/void closeSocket(Socket socket) {try {socket.close();} catch (IOException ex) {ex.printStackTrace();}System.out.println(socket + "离开了HTTP服务器");}/*** 读取一个图像文件的内容并返回给浏览器端.* @param fileName 文件名* @param socket 客户端 socket.*/void imgDownload(String fileName, Socket socket) {try {PrintStream out = new PrintStream(socket.getOutputStream(), true);File fileToSend = new File(fileName);if (fileToSend.exists() && !fileToSend.isDirectory()) {out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答out.println("Content-Type: application/octet-stream");out.println("Content-Length: " + fileToSend.length());// 返回内容字节数out.println();// 根据 HTTP 协议, 空行将结束头信息FileInputStream fis = new FileInputStream(fileToSend);byte data[] = new byte[fis.available()];fis.read(data);out.write(data);//文件下载完后关闭socket流,但socket还没有关闭out.close();fis.close();}} catch (Exception e) {e.printStackTrace();}}/*** 读取一个文件的内容并返回给浏览器端.* @param fileName 文件名* @param socket 客户端 socket.*/void fileDownload(String fileName, Socket socket) {try {PrintStream out = new PrintStream(socket.getOutputStream(), true);File fileToSend = new File(fileName);if (fileToSend.exists() && !fileToSend.isDirectory()) {out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答out.println("Content-Type: application/octet-stream;charset=" + encoding);/* Content-Disposition不是标准参数,查看一下HTTP/1.1的规范文档,对于这个参数的解释大意如下: * Content-Disposition参数本来是为了在客户端另存文件时提供一个建议的文件名,但是考虑到安全的原因, * 就从规范中去掉了这个参数。但是由于很多浏览器已经能够支持这个参数,所以只是在规范文档中列出,但是要 * 注意这个不是HTTP/1.1的标准参数。其值为“attachment”,那么无论这个文件是何类型,浏览器都会提示我 * 们下载此文件,因为此时它认为后面的消息体是一个“附件”,不需要由浏览器来处理了。 */out.println("Content-Disposition: attachment;filename=测试下载文件.txt");//out.println("Accept-Ranges: bytes");out.println("Content-Length: " + fileToSend.length());// 返回内容字节数out.println();// 根据 HTTP 协议, 空行将结束头信息FileInputStream fis = new FileInputStream(fileToSend);byte[] tmpByteArr = new byte[10];//这里为了测试看下载进度条,所以设置小点while (fis.available() > 0) {int readCount = fis.read(tmpByteArr);out.write(tmpByteArr, 0, readCount);}//文件下载完后关闭socket流out.close();fis.close();}} catch (Exception e) {e.printStackTrace();}}/*public static void main(String[] args) {PORT = 8080;}*/}

package com.example.jumptest;import java.io.IOException;import java.net.ServerSocket;import com.example.jumptest.httpserver.HttpServer;import com.example.jumptest.simpleHttpServer.SimpleHttpServer;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.webkit.WebView;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity {    Button button1;    Button button2;    WebView webView;Handler myHandler = new Handler() {          public void handleMessage(Message msg) {               // 实例化Intent              Intent it = new Intent(getApplicationContext(),XActivity.class);            it.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);            //设置Intent的Action属性              //it.setAction(msg.obj.toString());              // 启动Activity       //      webview.loadUrl("http://baidu.com");            startActivity(it);        }      }; @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button1=(Button)findViewById(R.id.button1);        button2=(Button)findViewById(R.id.button2);        webView=(WebView)findViewById(R.id.webView1);        button1.setOnClickListener(new OnClickListener() {        @Overridepublic void onClick(View arg0) {/*new Thread( new Runnvable() {         public void run() {           HttpServer server = new HttpServer();         server.await();        }            }).start();*/new SimpleHttpServer(myHandler);    Toast.makeText(MainActivity.this, "http服务启动成功", Toast.LENGTH_LONG).show();   // startService(new Intent("com.demo.SERVICE_DEMO"));}});           }}

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.example.jumptest"    android:versionCode="1"    android:versionName="1.0" >    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    <uses-permission android:name="android.permission.INTERNET" >    </uses-permission>    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="18" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="com.example.jumptest.MainActivity"            android:label="@string/app_name"             android:exported="true"             >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <activity            android:name="com.example.jumptest.XActivity"            android:label="@string/title_activity_x"             android:exported="true"            >        </activity>        <activity            android:name="com.example.jumptest.YActivity"            android:label="@string/title_activity_y"            android:exported="true"             >        </activity>    </application></manifest>


0 0