再网上查了好多资料,发现更新安卓7.0以上很少,折磨了很多天,整理一下,代码是俩篇文章合在一块的,也是为了方便大家不要浪费时间,重蹈我的覆辙,
如有侵权,联系小弟立马删除(嘿嘿)
1.下载apk
IEnumerator InstallApk()
{
WWW www = new WWW(url);
//下载需要更新的apk
while (true)
{
Debug.Log(www.progress / 1f * 100);
if (www.isDone)
{
break;
}
yield return null;
}
if (!string.IsNullOrEmpty(www.error))
{
Debug.Log("error:" + www.error);
yield return 0 ;
}
try
{
//将apk写入沙盒目录
string path = Application.persistentDataPath + "/test.apk";
File.WriteAllBytes(path, www.bytes);
using(AndroidJavaClass cl = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using(AndroidJavaObject ob = cl.GetStatic<AndroidJavaObject>("currentActivity"))
{
//然后调用android来安装apk
ob.Call("InstallApk", path);
}
}
}
catch (System.Exception e)
{
Debug.Log(e);
}
}
在unity打包的apk中,一般来说,调用Android方式,通过类似
obj = new AndroidJavaObject("android.content.Intent")
obj .Call<方法返回类型>("方法名", 参数);
这样的方式调用来实现一些简单的功能,但是当实现比较复杂的功能或者代码量比较多的时候就需要考虑使用jar包或者在unity中引用库。由于是在unity中引用,所以jar包和引用库的制作和集成和原生开发有少许不同:
1.1 制作jar包并使用
以在eclipse环境下制作为例:
- 首先在C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes目录下拿到class.jar放入jar工程中
- 继承UnityPlayerActivity,如果重写onCreate方法去掉其中的setContentView()
- 编写自己的功能接口(继承了的好处就是在编写时候可以用UnityPlayer.currentActivity当作上下文,否则就用
UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity")
获取上下文) - 用Export导出Jar放入Unity 的 Assets/plugins/Android/下
- 在C#脚本中通过
AndroidJavaClass obj = new AndroidJavaClass("类的全路径"); obj.CallStatic<接口返回类型>("接口名", 参数 );
调用
1.2 制作引用库
当接口功能中涉及一些权限,资源使用的时候仅仅有jar包是不够的,那么怎么把资源也同时引用进来呢
unity下的引用库目录结构:
Assets
| Plugins
|--MyCustomResources
|-- libs
|-- res
| |--- values
| |--- values-en
|-- project.properties
|-- Androidmanifest.xml
注意 project.properties和Androidmanifest.xml不能少,否则不能成功打包,其他资源参考Android工程结构目录添加
二、唤起安装界面
在android 7.0之前,实现唤起仅需要就能实现
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(install);
7.0之后由于系统加入了访问限制,系统的安装程序直接访问不了安装包,
对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。
如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。
要在应用间共享文件,您应发送一项 content:// URI,并授予 URI 临时访问权限。
进行此授权的最简单方式是使用 FileProvider 类。如需了解有关权限和共享文件的详细信息,请参阅共享文件。
--摘自Android developer
由于这个原因上面的操作在7.0以上设备上就毫无反映,虽然系统的安全更加可靠了,对于开发者来说变得麻烦了。。。 那就只好配置本应用的provider来解决了
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="packagename.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
filepaths文件、
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="apk"/>
</paths>
</resources>
应用下载的目标位置在存储根目录,在其他目录要更改paths节点下的内容
更改后的唤起安装页面的实现
if(Build.VERSION.SDK_INT>=24) {
Uri apkUri = FileProvider.getUriForFile(UnityPlayer.currentActivity, UnityPlayer.currentActivity.getPackageName() + ".fileProvider", file);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
UnityPlayer.currentActivity.startActivity(install);
} else{
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
UnityPlayer.currentActivity.startActivity(install);
}
三、最后
Android的安装功能实现起来并不复杂,主要是怎么在unity下调用Android的方法以及类库的引用方式才是需要学习和记录的地方,最后希望能对阅读者有所帮助!
链接: https://pan.baidu.com/s/1QIZqq8no7Cm2mtgbZHAMNg 提取码: w6h7
下载直接导入U3D 直接在U3D下一个方法调用即可
AndroidJavaClass obj = new AndroidJavaClass("com.am1105.installapk.MainActivity");
obj.CallStatic<bool>("invokeAndroidInstallPage",
“apk文件的路径”
);