I am working on an an app for a client and extending the unity player activity to help me do some android specific tasks.
I do this so I can capture results from a startActivityForResult
call, and so I can return from my activities back to Unity.
What I would like some advice on is how I can change this so it's not mixed in with my extended Unity player activity, but it is it's own activity that still captures the results and return the user back to the main Unity activity when finished.
I am hoping to not have to hide unity and instead have a new activity on the activity stack. I'm just unsure how I should go about it or if I have the thought process correct (please correct me if I am wrong)
This is my code that currently works but minimises Unity while it does my task:
public class MyActivity extends UnityPlayerActivity
{
private static final String MyTag = "######";
private static final int INSTALL_CODE = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(MyTag, "onCreate() -------------------------");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(MyTag, "onActivityResult() -------------------------" requestCode " --- " resultCode);
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == INSTALL_CODE)
{
// installed!
if (resultCode == -1)
UnityPlayer.UnitySendMessage("Canvas_CloudDeploy", "AndroidAPKInstallCallback", "true");
else
UnityPlayer.UnitySendMessage("Canvas_CloudDeploy", "AndroidAPKInstallCallback", "false");
}
}
@Override protected void onStop()
{
Log.i(MyTag, "onStop() -------------------------");
super.onStop();
}
// Quit Unity
@Override protected void onDestroy ()
{
Log.i(MyTag, "onDestroy() -------------------------");
super.onDestroy();
}
// Pause Unity
@Override protected void onPause()
{
Log.i(MyTag, "onPause() -------------------------");
super.onPause();
}
// Resume Unity
@Override protected void onResume()
{
Log.i(MyTag, "onResume() -------------------------");
super.onResume();
}
}
Unity calling code:
using AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
using AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
using AndroidJavaObject unityContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext");
string packageName = unityContext.Call<string>("getPackageName");
string authority = packageName ".provider";
AndroidJavaClass intentClass = new AndroidJavaClass ("android.content.Intent");
string ACTION_VIEW = intentClass.GetStatic<string>("ACTION_VIEW");
AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);
int FLAG_GRANT_READ_URI_PERMISSION = intentClass.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");
int FLAG_GRANT_WRITE_URI_PERMISSION = intentClass.GetStatic<int>("FLAG_GRANT_WRITE_URI_PERMISSION");
string EXTRA_RETURN_RESULT = intentClass.GetStatic<string>("EXTRA_RETURN_RESULT");
int FLAG_ACTIVITY_CLEAR_TASK = intentClass.GetStatic<int>("FLAG_ACTIVITY_CLEAR_TASK");
using AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
using AndroidJavaClass fileProvider = new AndroidJavaClass("androidx.core.content.FileProvider");
object[] providerParams = new object[3];
providerParams[0] = unityContext;
providerParams[1] = authority;
providerParams[2] = fileObj;
using AndroidJavaObject uri = fileProvider.CallStatic<AndroidJavaObject>("getUriForFile", providerParams);
intentObject.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
intentObject.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_CLEAR_TASK );
intentObject.Call<AndroidJavaObject>("addFlags", FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
intentObject.Call<AndroidJavaObject>("putExtra", EXTRA_RETURN_RESULT, true);
currentActivity.Call("startActivityForResult", intentObject, 100);
My android Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player" xmlns:tools="http://schemas.android.com/tools">
<application android:requestLegacyExternalStorage="true">
<activity android:name="net.****.****.MyActivity" android:theme="@style/UnityThemeSelector" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="unity.splash-mode" android:value="0" />
<meta-data android:name="unity.splash-enable" android:value="True" />
</application>
<uses-feature android:glEsVersion="0x00030000" />
<uses-feature android:name="android.hardware.vulkan.version" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
To summarise my questions are:
- When my activities run, because of how I call them in Unity, Unity is always stopped, then resumed. Can it simply be a new android activity running over the top of the Unity activity?
- If so, what's the right way to do it. I believe I need to call my activity from the extended unity class above, and pass in the unity context to it, so it knows how to get back once finished. But - I am a unsure. Lots of half examples to try and piece together.
- I need my activity to call back into the main unity activity once finished. It will need to send back the activity result and then resume the unity activity. I am doing this above, but want this in that separate activity class.
- If I use
FLAG_ACTIVITY_NEW_TASK
I almost get the behaviour I like (Shows android activity on top of mine), but you cant use that flag when requesting an activity result and it wont work as desired.
CodePudding user response:
Based on the above information, try using FLAG_ACTIVITY_NEW_DOCUMENT
which starts an activity as the new root of an existing task, allowing the user to navigate back to the previous task when it finishes. Unlike FLAG_ACTIVITY_NEW_TASK
, it doesn't clear the existing task.
Be sure to note that this flag should only be used when the activity is the primary entry point of a task (which it is in your case) and doesn't have any entry point ancestors in the task's stack.
using AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
using AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
using AndroidJavaObject unityContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext");
string packageName = unityContext.Call<string>("getPackageName");
string authority = packageName ".provider";
AndroidJavaClass intentClass = new AndroidJavaClass ("android.content.Intent");
string ACTION_VIEW = intentClass.GetStatic<string>("ACTION_VIEW");
AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);
int FLAG_GRANT_READ_URI_PERMISSION = intentClass.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");
int FLAG_GRANT_WRITE_URI_PERMISSION = intentClass.GetStatic<int>("FLAG_GRANT_WRITE_URI_PERMISSION");
int FLAG_ACTIVITY_NEW_DOCUMENT = intentClass.GetStatic<int>("FLAG_ACTIVITY_NEW_DOCUMENT");
using AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
using AndroidJavaClass fileProvider = new AndroidJavaClass("androidx.core.content.FileProvider");
object[] providerParams = new object[3];
providerParams[0] = unityContext;
providerParams[1] = authority;
providerParams[2] = fileObj;
using AndroidJavaObject uri = fileProvider.CallStatic<AndroidJavaObject>("getUriForFile", providerParams);
intentObject.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
intentObject.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_DOCUMENT );
intentObject.Call<AndroidJavaObject>("addFlags", FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
currentActivity.Call("startActivityForResult", intentObject, INSTALL_CODE);