转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5395715.html

需求:想让用户扫描一个二维码就能下载APP,并统计被扫描次数。

两种实现方法:

1.一般我们用草料生成二维码,如果没有注册的话只能生成一个包含下载网址的静态码,没有统计功能,而且出了自己截图保存外,草料是不会保存你的二维码的。

如果注册草料后,可以选择生成活码。所谓活码,就是一个指向页面,然后通过这个指向页面,再到你的下载链接。这个指向页面内嵌了统计代码。你可以通过草料的统计功能,看你的二维码相关的扫描数据。

2.你的App下载地址,自己内嵌一个统计代码,这样来统计扫描数据,这样,你只要一个静态码就够了。不需要在草料注册,用户扫描二维码后,直接进入下载界面,没有中间的指向页面。

由于不希望自己的app投放到应用市场,因此微下载行不通。比如,把你的APK文件上传到腾讯的开放平台,申请通过后,会拿到一个移动推广链接,然后替换原来的“android下载”的链接(直接此文件生成一个二维码也行),这样用户就可以在微信中扫一扫直接下载了。

同时,一般用户用扫一扫,大多都用微信自带“扫一扫”工具,而微信打开的二维码页面,会自动屏蔽apk文件,所有显然把apk的url生成一个二维码,让用户扫一扫后就能直接下载,这样是行不通的。微信做了限制除了和微信有合作关系的应用才能使用微信扫描后直接下载apk,其他的应用只能点击微信右上角的菜单跳转到普通浏览器下载apk。

尝试:

用草料生成二维码:

“文件”方式生成二维码:上传需要下载的文件,生成二维码,扫描二维码跳转到它默认的模板页面,点击可下载该文件。但是不支持.apk这样的特殊格式。

“网址”方式生成二维码:直接将.apk的下载地址url生成二维码,扫描下载行不通。微信将其屏蔽了(QQ中的“扫一扫”功能是可以的,易信、360也都可以扫出来)。

所以最终采用第二种方法。

实现方案:

直接判断微信的ua,然后弹出一个遮罩提示用户在新的浏览器中打开下载,并且加关闭的按钮,类似于如图。

(1)在你的服务器上写一个下载详情页面,将app下载链接放上去。这里设计的是:使用JS+HTML+CSS结合的方式,用移动h5技术适配了手机版网页,不会在已进入微信就弹出提示它在新浏览器中打开,因为你还可以在这个页面里做一些提交表单查看信息等操作。只有用户点击应用下载链接才弹出遮罩提示跳转至新的浏览器下载,如图:

(2)把下载页面的URL地址,通过"草料二维码"生成一个二维码,如图:

(3)如果是在微信里扫一扫打开的,当用户点击“安卓版下载”的时候,就提示用户要在默认浏览器中打开,如图:

(4)其实扫描二维码,就是访问一个url,可以在后台统计url被访问的次数,就是扫描二维码的次数了。

 贴出关键代码:

public class Counter{
private int count;
public Counter(){
this(0);
}
public Counter(int count){
this.count=count;
}
public void setCount(int count){
this.count=count;
}
public int getCount(){
return count;
}
public void add(int step){
count+=step;
}
}
/**
* 统计页面访问的次数,并在关闭应用时将其保存到文件,待下次启应用时读取次数。
* @author Joanna.Yan
*
*/
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
System.out.println("====================helloapp application is Initialized.=========="); ServletContext context=sce.getServletContext(); try{
BufferedReader reader = new BufferedReader(
new InputStreamReader(context.getResourceAsStream("/count/count.txt"))); int count = Integer.parseInt(reader.readLine());
reader.close();
Counter counter = new Counter(count);
context.setAttribute("counter",counter);
}catch(IOException e){e.printStackTrace();}
} public void contextDestroyed(ServletContextEvent sce){
System.out.println("helloapp application is Destroyed.");
ServletContext context=sce.getServletContext();
Counter counter=(Counter)context.getAttribute("counter"); if(counter != null){
try{
String filepath = context.getRealPath("/count");
filepath = filepath+"/count.txt";
PrintWriter pw= new PrintWriter(filepath);
pw.println(counter.getCount());
pw.close();
}catch(IOException e){e.printStackTrace();};
}
}
}

web.xml中注册监听器:

<listener>
<listener-class>joanna.yan.listener.MyServletContextListener</listener-class>
</listener>

web.xml中注册servlet:

  <servlet>
<servlet-name>QRCodeServlet</servlet-name>
<servlet-class>joanna.yan.servlet.QRCodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>QRCodeServlet</servlet-name>
<url-pattern>/QRCode</url-pattern>
</servlet-mapping>
public class QRCodeServlet extends HttpServlet{

    @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("QRCodeServlet被访问了!");
ServletContext context=getServletContext();
Counter counter=(Counter) context.getAttribute("counter");
if(counter==null){
counter=new Counter(1);
context.setAttribute("counter", counter);
}
counter.add(1);
System.out.println("被扫描的次数:"+counter.getCount());
resp.sendRedirect(""+req.getContextPath()+"/apkdownload.jsp");
}
}

设置适配移动端屏幕,禁止浏览器的缩放功能:

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0">

CSS+JS:

<style type="text/css">
#weixin-tip{display:none;position:fixed;left:0;top:0;background:rgba(0,0,0,0.8);filter:alpha(opacity=80);width:100%;height:100%;z-index:100;}
#weixin-tip p{text-align:center;margin-top:10%;padding:0 5%;position:relative;}
#weixin-tip .close{color:#fff;padding:5px;font:bold 20px/24px simsun;text-shadow:0 1px 0 #ddd;position:absolute;top:0;left:5%;}
</style> <script type="text/javascript">
var is_weixin = (function(){return navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1;})();
window.onload = function() {
var winHeight = typeof window.innerHeight != 'undefined' ? window.innerHeight : document.documentElement.clientHeight; //兼容IOS,不需要的可以去掉
var btn = document.getElementById('J_weixin');
var tip = document.getElementById('weixin-tip');
var close = document.getElementById('close');
if (is_weixin) {
btn.onclick = function(e) {
tip.style.height = winHeight + 'px'; //兼容IOS弹窗整屏
tip.style.display = 'block';
return false;
};
close.onclick = function() {
tip.style.display = 'none';
};
}
};
</script>
 ....你的网页代码......
<div id="weixin-tip">
<p>
<img alt="微信打开" src="img/warn.png">
<span id="close" title="关闭" class="close">X</span>
</p>
</div>

如果此文对您有帮助,微信打赏我一下吧~

扫二维码下载apk并统计被扫描次数(及微信屏蔽下载解决方案)的更多相关文章

  1. 网页授权——扫二维码获取openid

    最近做微信公众平台开发项目时遇到这样一个功能需求:生成一个特定url的二维码,用户扫描二维码后跳转到这个url指定的页面,并在这个页面获得用户的openid.这个功能主要涉及到两方面的技术:生成二维码 ...

  2. MISC-吹着贝斯扫二维码

    题目 [安洵杯 2019]吹着贝斯扫二维码 解压附件,有36个文件和一个压缩包,压缩包带密码和备注 分析 文件类型 随便打开一个不明文件,是jpg图片啊(FF D8 FF) 改一个试试,有一个小块二维 ...

  3. android DialogFragment 实现Dialog展示扫二维码图片展示

    近期开发项目,做个按钮点击弹出展示微信二维码关注微信公众号的展示框,于是想到DialogFragment,期间对Dialog的title的底框字体颜色做出相关设置,记录如下: 下面是 DialogFr ...

  4. 很多人很想知道怎么扫一扫二维码就能打开网站,就能添加联系人,就能链接wifi,今天说下这些格式,明天做个demo

    有些功能部分手机不能使用,网站,通讯录,wifi基本上每个手机都可以使用. 在看之前你可以扫一扫下面几个二维码先看看效果: 1.二维码生成 网址 (URL) 包含网址的 二维码生成 是大家平时最常接触 ...

  5. vue 实现 扫二维码 功能

    前段时间一直在研究,如何通过 vue 调用 相机 实现 扫一扫的功能,但是查看文档发现,需要获取 getUserMedia 的属性值,但存在兼容性问题. 退而求其次,通过 h5plus 来实现. 1. ...

  6. 扫二维码登录实现原理,php版

    基础的逻辑图就是这样,但是实际情况还是有几种可能 比如QQ登录,微信登录,微博登录,基本设计都差不多,根据实际情况会有一些差异 问题是,如果设计合理的接口在保证数据的安全性和快速性 设计到的技术不复杂 ...

  7. Android二维码的生成,解析以及扫描功能

    <1> 布局只有2个按钮,实现生成二维码和解析二维码 <Button android:layout_width="wrap_content" android:la ...

  8. uniapp 扫二维码跳转

    在h5和wxapp中 生成qrcode的组件 https://ext.dcloud.net.cn/plugin?id=39 wx小程序扫二位码文档 生成链接时 computed: { ...mapSt ...

  9. Android | 教你如何开发扫二维码功能

    前言   最近要做一个停车场扫码收费的app,在网上搜了一圈,首先接触到了ZXing,上手试了下,集成过程不复杂,但是感觉效果欠佳,比如距离稍微远点儿就扫不出来了,另外角度对的不好,反光或者光线比较暗 ...

随机推荐

  1. ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  2. CENTOS 6.5 平台离线安装 Apache2.4

    一.下载Apache 2.4 http://httpd.apache.org/download.cgi http://mirrors.cnnic.cn/apache//httpd/httpd-2.4. ...

  3. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  4. <译>通过PowerShell工具跨多台服务器执行SQL脚本

    有时候,当我们并没有合适的第三方工具(大部分需要付费)去管理多台数据库服务器,那么如何做最省力.省心呢?!Powershell一个强大的工具,可以很方便帮到我们处理日常的数据库维护工作 .简单的几步搞 ...

  5. 深入node之Transform

    Transform流特性 在开发中直接接触Transform流的情况不是很多,往往是使用相对成熟的模块或者封装的API来完成流的处理,最为特殊的莫过于through2模块和gulp流操作.那么,Tra ...

  6. 数塔问题(DP算法)自底向上计算最大值

    Input 输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数 ...

  7. 信息安全-1:python之playfair密码算法详解[原创]

    转发注明出处: http://www.cnblogs.com/0zcl/p/6105825.html 一.基本概念 古典密码是基于字符替换的密码.加密技术有:Caesar(恺撒)密码.Vigenere ...

  8. 数据库 DML、DDL、DCL区别 .

    总体解释: DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的 ...

  9. ORA-00821: Specified value of sga_target 3072M is too small, needs to be at least 12896M

    在测试PlateSpine克隆的数据库服务器时,由于资源有限,克隆过来的数据库服务器只给了9G的内存,结果在测试时,老是会出现OOMkiller导致宕机,即out of memory killer,是 ...

  10. 机器指令翻译成 JavaScript —— No.5 指令变化

    上一篇,我们通过内置解释器的方案,解决任意跳转的问题.同时,也提到另一个问题:如果指令发生变化,又该如何应对. 指令自改 如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的.然而,对应 ...