用浏览器跳转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
- 用浏览器跳转APP研究方案记录
- Android 浏览器跳转App
- Android平台好友点击微信分享的内容后跳转来源App的实现方案研究
- android app小白试水-fragment跳转浏览器debug
- 由浏览器跳转到自己的app
- DeepLink(浏览器点击链接跳转到app)
- 手机app中跳转调用外部浏览器
- android浏览器研究-APP层UI布局
- android浏览器研究-APP层基本架构
- 非微信内置浏览器中的网页调起微信支付的方案研究
- 安卓非微信内置浏览器中的网页调起微信支付的方案研究
- 填上浏览器跳转app-webview,app没有接收跳转url的查询参数的坑
- Activity跳转失效闪退问题解决方案记录
- ios 使用Safari浏览器跳转打开、唤醒app
- 移动端浏览器打开app或者跳转链接
- iOS App直接调用SafariController,不跳转到Safari浏览器
- App的URL跳转到手机浏览器(openSafari)
- 浏览器中唤起native app || 跳转到应用商城下载
- 题目:编写一个程序,创建一个单链表,需要完成以下要求 1. 用户输入一组整数,以0作为结束标志,将这一组整数存放在链表中(0不存放),并打印该链表中的值。 2. 删除第5个元素,并打印删除后的结
- iOS 大型项目开发漫谈
- Spring MVC详解(四) Controller接口控制器详解(1)
- 整理网上资料---C标准库值篇二 :标准库源码下载地址、标准库手册下载地址
- ios禁用多按钮同时点下的效果
- 用浏览器跳转APP研究方案记录
- SSDB分布式并发锁设计
- Java虚拟机类加载机制浅谈
- 多线程编程2-NSOperation
- Spring Quartz Java工程版和Web工程版示例
- 微信开发第五篇手机端微信公众号自定义菜单及OAuth2.0授权页面
- Windows系统下,查看端口占用情况杀掉端口占用进程
- 关于linux内核中的"__attribute__ ((packed))"
- vi/vim 注释字体颜色的设置