支持SMB的手机VR播放器(三):接收隐式intent

接前文,为了实现一个较为完整的播放器,需要支持从文件管理器中打开文件,而这一过程是通过接收隐式 intent 实现的。我们需要让 Unity 接收该隐式 intent。
声明 intent-filter
文件管理器打开一个应用时,会发送一个隐式 intent,系统会在应用的 AndroidManifest 中查找并匹配 intent-filter,之后将匹配成功的应用列出来供你选择(匹配规则见安卓开发文档)。
我们可以在 Unity Asset 目录的Plugins/Android/AndroidMainfest.xml
中声明所需的 intent-filter,如下所示:
安卓文件管理器中打开对应文件时,会弹出选择应用的弹窗:
接收 intent
接收 intent 单靠 Unity C# 是实现不了的,需要写一些安卓代码,同时也需要一些 C# 代码配合。我们的目的是,应用开启时判断自身是否是由隐式 intent 拉起的,如果是,则将 intent 中的参数传递给 Unity。
打开 AndroidStudio,新建空工程,创建一个 Module,之后写几行简单的 Java 代码(本人 Unity C# 脚本小子,对 Java 不熟,勿喷脚本质量):
public class MiaoPlayerEngine {
static MiaoPlayerEngine _instance;
protected Activity _unityActivity;
//获取单例
public static MiaoPlayerEngine getInstance(Context unityActivity){
if(_instance == null){
_instance = new MiaoPlayerEngine();
_instance._unityActivity = (Activity) unityActivity;
}
return _instance;
}
//获取 ActivityIntent
public String getActivityIntent(){
Intent intent = _instance._unityActivity.getIntent();
if(intent != null && intent.getData() != null){
//TODO:only for test, 对于 uri content://media/external/xxx 来说需要处理才能给 Unity 用
try {
return getRealPath(intent.getData());
}catch(Exception e){
System.err.println(e.toString());
return intent.getData().toString();
}
}else{
System.out.println("getIntentIs Null");
return "";
}
}
//https://stackoverflow.com/a/10564727,测试代码,将 content://media/external/xxx 转成绝对路径
public String getRealPath(Uri contentUri){
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(_unityActivity.getApplicationContext(), contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
public void OnDestroy(){
_instance = null;
}
}
之后写一段 C# 代码用来生成上面的 Java 类,并调用其方法获取 intent 数据,关键代码如下:
public void Awake(){
AndroidJavaClass playerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = playerClass.GetStatic<AndroidJavaObject>("currentActivity");
jc = new AndroidJavaClass("com.azimiao.miaoplayerhelper.MiaoPlayerEngine");
jo = jc?.CallStatic<AndroidJavaObject>("getInstance", activity);
if(jo == null)
{
Debug.LogError("ZAX MiaoPlayerEngine obj is null");
}
}
public string GetIntent()
{
if(jo != null)
{
string f = jo?.Call<string>("getActivityIntent");
if (!string.IsNullOrEmpty(f))
{
Debug.Log("GetIntent is:" + f);
}
else
{
Debug.Log("GetIntent is empty");
}
return f;
}
return string.Empty;
}
真机运行
真机运行时,直接打开应用,获取 intent 数据为空:
通过文件管理器以打开方式弹窗的形式打开应用,获取到了 intent 路径数据:
至此,完成了 Unity 接收隐式 intent 的关键一步。
其他
虽然成功拿到了 intent 数据,但因为 Unity 端无法直接使用content://xxx
这种媒体库形式的链接,后续还需要解决 intent 中的 uri 路径处理问题。