计划改不上变化,之前是平台强更APK,功能都已经完善了,都线上测试过。现在改成需要我们这边来操作,好吧,那就来研究下。
跟之前一样,为了省事,安装APK的代码也放到之前写的jar包中。代码,其实很简单。但是 Android N为了安全考虑,需要使用 fileprovider 机制来访问、打开 APK 文件。这个地方就卡了我一个下午加晚上的时间来搞,记录一下。
Java代码:
/**
* 安装APK
*/
public void InstallAPK(Object object, String apkPath)
{
Activity activity = (Activity)object;
if(activity != null) {
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
File apkFile = new File(apkPath);
Uri uri;
if(Build.VERSION.SDK_INT >= 24)
{
uri = FileProvider.getUriForFile(activity.getApplicationContext(), activity.getPackageName() + ".fileprovider", apkFile);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}else
uri = Uri.fromFile(apkFile);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
activity.getApplicationContext().startActivity(installIntent);
}
}
AndroidManifest.xml上的修改:
<!-- 添加权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application
---------------------------------------
>
<!-- authorities中的大小写要注意下 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity
---------------------------------------
</activity>
</application>
android:resource="@xml/file_paths",看到这个xml文件吗?你需要在Unity上添加这个xml文件。
目录:
file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path
name="files"
path="" />
</paths>
</resources>
注意,踩坑的地方到了:
1.java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/content/FileProvider。如果报了这个错误,需要在Unity上添加android-support-v4.jar。看上面的截图。
2.java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourcePar错误。注意AndroidManifest.xml配置上android:authorities的名称是否对的,大小写也注意下
3.android.content.res.XmlResourceParser错误。跟第2个错误一样。
其实就大小写的问题卡了很久,fileProvider和fileprovider不仔细看,还真不注意,记录下来,省的下次再犯这个错误。
C#上的测试代码:
public class Test : MonoBehaviour {
AndroidJavaObject currentActivity;
AndroidJavaClass apiClass;
AndroidJavaObject apiInstance;
/// <summary>
/// 获取当前Activity
/// </summary>
/// <returns></returns>
AndroidJavaObject GetCurrentActivity()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (null == currentActivity)
currentActivity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
#endif
return currentActivity;
}
/// <summary>
/// 获取安卓工具类实例
/// </summary>
/// <returns></returns>
private AndroidJavaObject GetApiInstance()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (null == apiInstance)
{
if (null == apiClass)
apiClass = new AndroidJavaClass("com.zp.utility.api");
apiInstance = apiClass.CallStatic<AndroidJavaObject>("instance");
}
#endif
return apiInstance;
}
void InstallAPK(string apkPath)
{
Debug.LogError("apkPath: " + apkPath);
#if UNITY_ANDROID && !UNITY_EDITOR
var apiInstance = GetApiInstance();
var activity = GetCurrentActivity();
if(apiInstance != null && activity != null)
{
apiInstance.Call("InstallAPK", activity, apkPath);
}
#endif
}
private void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 100), "InstallAPK"))
{
InstallAPK(Application.persistentDataPath + "/" + "test.apk");
}
}
}
还查到个解决方法是在Application.onCreate加入如下代码,这个没有测试:
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();