Android开发学习之路-插件安装、检查应用是否安装解决方案
使用Bmob的时候,如果需要用到支付功能,就需要让应用去安装一个支付插件。而一般的做法是将插件放置在assets目录中,当用户需要支付,先检查是否能支付,不能的话,提示安装插件。代码:
public class InstallHelper {
private static final String TAG = "InstallHelper";
private Context mContext;
InstallHelper(Context context) {
mContext = context;
}
void installAssetApk(String fileName) {
try {
InputStream is = this.mContext.getAssets().open(fileName);
File file = new File(mContext.getExternalCacheDir()+ File.separator +
"demo.apk");
if (file.exists()) {
file.delete();
}
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int i;
while ((i = is.read(bytes)) > 0) {
fos.write(bytes, 0, i);
}
fos.close();
is.close();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + file), "application/vnd.android" + "" +
".package-archive");
mContext.startActivity(intent);
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们不能直接执行assets下的安装包,所以这里的做法是先获得Assets目录的输入流。接着创建一个文件,这个文件用来存放我们从assets目录下读出的安装包内容。上述代码中的12和13行中,我们通过getExternalCacheDir()来获取主要存放的目录,再通过File.separator来插入一个路径分隔符,最后填上文件名来作为整个文件的绝对路径。这里有一个地方要说明,先看下面两个方法:
getExternalCacheDir():获取应用目录下的cache目录,不需要读写权限,应用删除时也会删除
getExternalStorageDirectory():获取主外部储存的根目录,需要读写权限,应用删除不会删除
因为这个插件不需要共享给其他应用,所以我们需要使用第一个方法。如果使用了第二个,则会破坏掉用户外部储存的目录结构,毕竟无端的多出了一个文件,用户感觉当然是不好的。
接着判断文件是否存在,若存在则重新建立。再创建一个byte数组来进行数据读写操作的辅助,不断地从输入流中读入数据,写到文件中。但是这里有一个问题要注意,我们传输的是一个安装包,只要最后传输的文件和assets目录下的安装包有一点不同,那么这个安装包都是不能使用的(安装会提示解析出错)。这里要留意的地方就是22行,这个write方法不能写错。
如果我们直接使用:
fos.write(bytes); // 相当于fos.write(bytes, 0, bytes.length),也就是把整个bytes数组写入输出流
则这个传输就不正确了,这里先想想为什么?可以看到,我们定义了一个局部变量i来获取每次读入的大小,只要这个i的值不为-1,则循环一直进行。但是试想最后一次循环的时候,假设数据只有500个byte,那么我们直接调用fos.write(bytes)则是相当于把整一个bytes数组都写进输出流,但是实际上我们只需要前500个。
当读写完全后,我们可以通过Intent来打开这个安装包,写法就是上面那样。
另一个内容就是检查一个应用是否已经安装,例如我们在调用微信分享的时候,如果用户手机中没有微信,那么App将会没任何反应,这不会是是我们希望看到的,所以一般会先判断微信是否已经安装(其他应用类似)。
判断一个App是否已经安装,我在StackOverFlow中看到的很多方法都是直接的使用PackageManager来获取所有Activity对应的PackageInfo,代码如下:
private boolean isWechatInstall() {
List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages
(PackageManager.GET_ACTIVITIES);
for (PackageInfo p : installedPackages) {
if (p.packageName.equals("com.tencent.mm")) {
return true;
}
}
return false;
}
实际上这样做是不行的。原因是系统中的应用Activity对应的Package是很多的,如果在短时间内对这些信息进行包装,则会抛出异常并终止处理(一般处理30个左右就会自动终止),因为这个异常不是RuntimeException,所以我们的App也不会Crash掉,只是结果不正确。
正确的做法应该是这样:
private boolean isAppInstalled(String packageName) {
PackageManager pm = getPackageManager();
boolean installed;
try {
pm.getPackageInfo(packageName, PackageManager
.GET_ACTIVITIES);
installed = true;
} catch (PackageManager.NameNotFoundException e) {
installed = false;
}
return installed;
}
直接根据包名获取其PackageInfo对象,如果不存在,则在抛出的异常中返回false即可。
Android开发学习之路-插件安装、检查应用是否安装解决方案的更多相关文章
- Android开发学习之路--Android Studio cmake编译ffmpeg
最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...
- Android开发学习之路--网络编程之xml、json
一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ...
- Android开发学习之路--Android系统架构初探
环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...
- Android开发学习之路--MAC下Android Studio开发环境搭建
自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ...
- Android开发学习之路-RecyclerView滑动删除和拖动排序
Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...
- Android开发学习之路--基于vitamio的视频播放器(二)
终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ...
- Android开发学习之路--Activity之初体验
环境也搭建好了,android系统也基本了解了,那么接下来就可以开始学习android开发了,相信这么学下去肯定可以把android开发学习好的,再加上时而再温故下linux下的知识,看看androi ...
- Android开发学习之路-Android Studio开发小技巧
上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ...
- Android开发学习之路--React-Native之初体验
近段时间业余在学node.js,租了个阿里云准备搭建后端,想用node.js,偶尔得知react-native可以在不同平台跑,js在iOS和android上都可以运行ok,今天就简单学习下rea ...
随机推荐
- In-Memory:内存数据库
在逝去的2016后半年,由于项目需要支持数据的快速更新和多用户的高并发负载,我试水SQL Server 2016的In-Memory OLTP,创建内存数据库实现项目的负载需求,现在项目接近尾声,系统 ...
- EntityFramework Core Raw SQL
前言 本节我们来讲讲EF Core中的原始查询,目前在项目中对于简单的查询直接通过EF就可以解决,但是涉及到多表查询时为了一步到位就采用了原始查询的方式进行.下面我们一起来看看. EntityFram ...
- Windows 7上执行Cake 报错原因是Powershell 版本问题
在Windows 7 SP1 电脑上执行Cake的的例子 http://cakebuild.net/docs/tutorials/getting-started ,运行./Build.ps1 报下面的 ...
- 记一个mvn奇怪错误: Archive for required library: 'D:/mvn/repos/junit/junit/3.8.1/junit-3.8.1.jar' in project 'xxx' cannot be read or is not a valid ZIP file
我的maven 项目有一个红色感叹号, 而且Problems 存在 errors : Description Resource Path Location Type Archive for requi ...
- document.documentElement.clientHeight 与 document.body.clientHeight(杜绝千篇一律的抄袭!!)
document.documentElement.clientHeight 与 document.body.clientHeight用来获取页面可视高度我觉得有点问题.这两个应该不是一个东西. 页面中 ...
- js获取给定月份的N个月后的日期
1.在讲js获取给定月份的N个月后的日期之前,小颖先给大家讲下getFullYear().getYear()的区别. ①getYear() var d = new Date() console.log ...
- JavaScript权威指南 - 对象
JavaScript对象可以看作是属性的无序集合,每个属性就是一个键值对,可增可删. JavaScript中的所有事物都是对象:字符串.数字.数组.日期,等等. JavaScript对象除了可以保持自 ...
- 算法与数据结构(十一) 平衡二叉树(AVL树)
今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...
- 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler
熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...
- IdentityServer4 使用OpenID Connect添加用户身份验证
使用IdentityServer4 实现OpenID Connect服务端,添加用户身份验证.客户端调用,实现授权. IdentityServer4 目前已更新至1.0 版,在之前的文章中有所介绍.I ...