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 ...
随机推荐
- 避免重复造轮子的UI自动化测试框架开发
一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...
- [APUE]进程控制(上)
一.进程标识 进程ID 0是调度进程,常常被称为交换进程(swapper).该进程并不执行任何磁盘上的程序--它是内核的一部分,因此也被称为系统进程.进程ID 1是init进程,在自举(bootstr ...
- 发布:.NET开发人员必备的可视化调试工具(你值的拥有)
1:如何使用 1:点击下载:.NET可视化调试工具 (更新于2016-12-29 19:11:00) (终于彻底兼容了部分VS环境下无法使用的问题) 2:解压RAR后执行:CYQ.VisualierS ...
- CSS3 3D立方体效果-transform也不过如此
CSS3系列已经学习了一段时间了,第一篇文章写了一些css3的奇技淫巧,原文戳这里,还获得了较多网友的支持,在此谢过各位,你们的支持是我写文章最大的动力^_^. 那么这一篇文章呢,主要是通过一个3D立 ...
- 用scikit-learn学习DBSCAN聚类
在DBSCAN密度聚类算法中,我们对DBSCAN聚类算法的原理做了总结,本文就对如何用scikit-learn来学习DBSCAN聚类做一个总结,重点讲述参数的意义和需要调参的参数. 1. scikit ...
- Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用
通过本文你将学会如下内容: 1,如何使用Xamarin开发跨平台(Windows,Android,iOS)应用. 2,如何使用微软的登录界面登入Microsoft账号. 3,如何使用Outlook邮箱 ...
- EF6 对多个数据库,多个DBContext的情况 进行迁移的方法。
参见: http://stackoverflow.com/questions/21537558/multiple-db-contexts-in-the-same-db-and-application- ...
- git init和git init -bare区别
1 Git init 和 git init –bare 的区别 用"git init"初始化的版本库用户也可以在该目录下执行所有git方面的操作.但别的用户在将更新push上来的 ...
- Windows下Redis缓存服务器的使用 .NET StackExchange.Redis Redis Desktop Manager
Redis缓存服务器是一款key/value数据库,读110000次/s,写81000次/s,因为是内存操作所以速度飞快,常见用法是存用户token.短信验证码等 官网显示Redis本身并没有Wind ...
- Configure a VLAN (on top of a bond) with NetworkManager (nmcli) in RHEL7
not on top of a bond Environment Red Hat Enterprise Linux 7 NetworkManager Issue Need an 802.1q VLAN ...