You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Meta Quest中Unity主应用启动独立APK应用的问题排查

在Meta Quest设备上实现主应用启动侧载APK的问题

背景

伦敦帝国理工学院团队正在搭建VR教育应用分发系统:

  • 桌面端方案:学习应用打包为AssetBundle+DLL上传服务器,主启动应用可下载后直接导入运行,无需单独安装每个应用。
  • 目标Quest端方案:因Android无法运行时加载DLL,计划将每个学习应用打包为独立APK,由主应用下载后启动,完全脱离Quest商店,仅需侧载主应用并开启未知来源/开发者模式,主应用编译时无需知晓待启动应用信息,仅通过包名调用。

APK的构建、上传、下载流程均正常,但主应用内启动APK的操作失败。

主应用启动代码

public void LaunchApp()
{
    Debug.Log("Try launch app 1");
    string packageName = "com.ImperialCollegeLondon.VE2Hub24"; //该包名可通过SideQuest或设备菜单正常启动
    var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    var packageManager = currentActivity.Call<AndroidJavaObject>("getPackageManager");
    var launchIntent = packageManager.Call<AndroidJavaObject>("getLaunchIntentForPackage", packageName);
    currentActivity.Call("startActivity", launchIntent);
}

运行时错误日志

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData(android.content.Context)' on a null object reference
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData(android.content.Context)' on a null object reference
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1756)
at android.app.Activity.startActivityForResult(Activity.java:5411)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:728)
at android.app.Activity.startActivityForResult(Activity.java:5369)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:709)
at android.app.Activity.startActivity(Activity.java:5755)
at android.app.Activity.startActivity(Activity.java:5708)
at UnityEngine.AndroidJNISafe.CheckException ()

待启动应用Manifest关键配置

主Activity为com.unity3d.player.UnityPlayerGameActivity,包含以下属性:

  • 动作:android.intent.action.MAIN
  • 类别:android.intent.category.LAUNCHER、com.oculus.intent.category.VR
  • exported=true

尝试修改后的错误

将代码中的var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");改为var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayerGameActivity");后,出现新错误:

java.lang.NoSuchFieldError: no "Ljava/lang/Object;" field "currentActivity" in class "Lcom/unity3d/player/UnityPlayerGameActivity;" or its superclasses
java.lang.NoSuchFieldError: no "Ljava/lang/Object;" field "currentActivity" in class "Lcom/unity3d/player/UnityPlayerGameActivity;" or its superclasses
at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.AndroidJNISafe.GetStaticFieldID (System.IntPtr clazz, System.String name, System.String sig) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine._AndroidJNIHelper.GetFieldID (System.IntPtr jclass, System.String fieldName, System.String signature, System.Boolean isStatic) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.AndroidJavaObject._GetStatic[FieldType] (System.String fieldName) [0x00000] in <00000000000000000000000000000000>:0
at WorldLauncher.LaunchApp2 () [0x00000] in < etc etc

问题分析与解决方案

核心问题

第一个错误的根源是getLaunchIntentForPackage返回了null,即使包名正确、应用已安装,也可能因为以下原因:

  1. Quest的VR应用需要明确指定VR启动类别,默认的launch intent可能无法正确识别。
  2. Unity打包的Quest应用,其启动Intent需要包含com.oculus.intent.category.VR才能被正确唤起,而getLaunchIntentForPackage可能没有自动包含这个类别。

修复后的代码

直接构建包含VR类别的Intent,而非依赖系统返回的默认launch intent:

public void LaunchVRApp()
{
    string packageName = "com.ImperialCollegeLondon.VE2Hub24";
    var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    
    // 构建明确的VR启动Intent
    var intentClass = new AndroidJavaClass("android.content.Intent");
    var intent = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic<string>("ACTION_MAIN"));
    intent.Call<AndroidJavaObject>("addCategory", "android.intent.category.LAUNCHER");
    intent.Call<AndroidJavaObject>("addCategory", "com.oculus.intent.category.VR");
    intent.Call<AndroidJavaObject>("setPackage", packageName);
    
    // 确保Intent可解析
    var packageManager = currentActivity.Call<AndroidJavaObject>("getPackageManager");
    var resolveInfo = packageManager.Call<AndroidJavaObject>("resolveActivity", intent, 0);
    if(resolveInfo != null)
    {
        currentActivity.Call("startActivity", intent);
        Debug.Log("Successfully launched VR app");
    }
    else
    {
        Debug.LogError("Cannot resolve intent for package: " + packageName);
    }
}

额外注意事项

  1. 权限配置:主应用的AndroidManifest.xml需要添加QUERY_ALL_PACKAGES权限(针对Android 11+),或者在<queries>标签中声明允许查询的包名(如果已知包名列表):
    <!-- 针对Android 11+,若允许查询所有包 -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
    
    <!-- 或者精确声明允许查询的包名 -->
    <queries>
        <package android:name="com.ImperialCollegeLondon.VE2Hub24" />
        <!-- 添加其他学习应用包名 -->
    </queries>
    
  2. Unity版本适配:确保主应用使用的Unity版本与待启动应用的Unity版本兼容,避免因Java层API差异导致的问题。
  3. Quest系统版本:部分新版本Quest系统对未知来源应用的启动有更严格的限制,需确保设备已开启开发者模式和允许未知来源应用。

关于Contractors等VR游戏的Mod实现

这类游戏的Mod并非通过加载DLL实现,而是采用以下方案:

  • 将Mod内容打包为AssetBundle,主游戏在运行时下载并加载这些资源包。
  • Mod的逻辑代码通过Lua、C#脚本的动态编译(利用Unity的CSharpCodeProvider)或预定义的扩展接口实现,无需直接加载外部DLL。

需求可行性确认

该需求完全可实现:

  • 侧载应用之间的启动是Android系统允许的行为,只要权限配置正确、Intent构建合理即可。
  • 已有大量第三方Quest应用分发平台(如SideQuest)采用类似的应用间启动逻辑。

内容的提问来源于stack exchange,提问作者Fred T.A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:18:16