使用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开发学习之路-插件安装、检查应用是否安装解决方案的更多相关文章

  1. Android开发学习之路--Android Studio cmake编译ffmpeg

      最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...

  2. Android开发学习之路--网络编程之xml、json

    一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ...

  3. Android开发学习之路--Android系统架构初探

    环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...

  4. Android开发学习之路--MAC下Android Studio开发环境搭建

    自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ...

  5. Android开发学习之路-RecyclerView滑动删除和拖动排序

    Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...

  6. Android开发学习之路--基于vitamio的视频播放器(二)

      终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ...

  7. Android开发学习之路--Activity之初体验

    环境也搭建好了,android系统也基本了解了,那么接下来就可以开始学习android开发了,相信这么学下去肯定可以把android开发学习好的,再加上时而再温故下linux下的知识,看看androi ...

  8. Android开发学习之路-Android Studio开发小技巧

    上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ...

  9. Android开发学习之路--React-Native之初体验

      近段时间业余在学node.js,租了个阿里云准备搭建后端,想用node.js,偶尔得知react-native可以在不同平台跑,js在iOS和android上都可以运行ok,今天就简单学习下rea ...

随机推荐

  1. 通过AngularJS实现前端与后台的数据对接(二)——服务(service,$http)篇

    什么是服务? 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性. 服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化) ...

  2. 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】

    说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...

  3. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(73)-微信公众平台开发-消息管理

    系列目录 前言 回顾上一节,我们熟悉的了解了消息的请求和响应,这一节我们来建立数据库的表,表的设计蛮复杂 你也可以按自己所分析的情形结构来建表 必须非常熟悉表的结果才能运用这张表,这表表的情形涵盖比较 ...

  5. 《JavaScript设计模式 张》整理

    最近在研读另外一本关于设计模式的书<JavaScript设计模式>,这本书中描述了更多的设计模式. 一.创建型设计模式 包括简单工厂.工厂方法.抽象工厂.建造者.原型和单例模式. 1)简单 ...

  6. CSharpGL(33)使用uniform块来优化对uniform变量的读写

    CSharpGL(33)使用uniform块来优化对uniform变量的读写 +BIT祝威+悄悄在此留下版了个权的信息说: Uniform块 如果shader程序变得比较复杂,那么其中用到的unifo ...

  7. python 3.5 成功安装 scrapy 的步骤

    http://www.cnblogs.com/hhh5460/p/5814275.html

  8. iOS 原生地图地理编码与反地理编码

    当我们要在App实现功能:输入地名,编码为经纬度,实现导航功能. 那么,我需要用到原生地图中的地理编码功能,而在Core Location中主要包含了定位.地理编码(包括反编码)功能. 在文件中导入 ...

  9. npm源切换

    版权声明:欢迎转载,请附加转载来源:一路博客(http://www.16boke.com)   目录(?)[+] 安装 使用 列出可选的源 切换 增加源 删除源 测试速度 许可 项目主页   我们介绍 ...

  10. 笔记:Memory Notification: Library Cache Object loaded into SGA

    笔记:Memory Notification: Library Cache Object loaded into SGA在警告日志中发现一些这样的警告信息:Mon Nov 21 14:24:22 20 ...