Unity3D access variable set through Xcode - c#

I am creating an app that uses the devices camera.
I need to implement a function that checks if the user has allowed the app to access the devices camera, if they have not, the scene that uses the camera just shows a black screen.
Because Unity only supports Application.HasUserAuthorization in the webplayer platform I need to add the authorization check to the project through XCode after build.
Firstly I added the following code to didFinishLaunchingWithOptions in the UnityAppController.mm file:
// Determine camera access on iOS >= 7
if ([AVCaptureDevice respondsToSelector:#selector(requestAccessForMediaType:completionHandler:)]) {
// Completion handler will be dispatched on a separate thread
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (YES == granted) {
// User granted access to the camera, continue with app launch
CameraIsAvailable = YES;
CameraCheckDone = YES;
}
else {
CameraIsAvailable = NO;
CameraCheckDone = YES;
}
}];
}
else {
// iOS < 7 (camera access always OK)
CameraCheckDone = YES;
// Continue with app launch...
}
and the follwoing code to applicationDidBecomeActive
while (!CameraCheckDone) { }
if(!CameraIsAvailable){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Authorize Camera"
message:#"Instructions go here"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
The result is that every time the app is run, a popup appears instructing the user to activate the camera, which is progress, but they still have access to the scene that shows the black screen instead of the camera view.
Is there any way that I can access the CameraIsAvilable variable from within Unity?
Any suggestions would be greatly appreciated! TIA!

I solved the problem by using the UnitySendMessage function.
Firstly I updated didFinishLaunchingWithOptions in UnityAppController.mm, here is the modified code:
// Determine camera access on iOS >= 7
if ([AVCaptureDevice respondsToSelector:#selector(requestAccessForMediaType:completionHandler:)]) {
// Completion handler will be dispatched on a separate thread
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (YES == granted) {
// User granted access to the camera, continue with app launch
CameraIsAvailable = YES;
CameraCheckDone = YES;
// ADDED THE FOLLOWING LINE THAT SENDS VALUE "YES" WHEN CAMERA ALLOWED
UnitySendMessage("iOSManager", "cameraCheck", "YES");
}
else {
CameraIsAvailable = NO;
CameraCheckDone = YES;
// ADDED THE FOLLOWING LINE THAT SENDS VALUE "NO" WHEN CAMERA IS NOT ALLOWED
UnitySendMessage("iOSManager", "cameraCheck", "NO");
}
}];
}
else {
// iOS < 7 (camera access always OK)
CameraCheckDone = YES;
// Continue with app launch...
}
Then in Unity3D, I added a GameObject called "iOSManager" to the first scene of my game (note: the GameObject name must match the first parameter of the UnitySendMessage function).
I created the following script with the cameraCheck() function (the function name matches the second parameter of the UnitySendMessage function):
#if UNITY_IOS
void cameraCheck(string value)
{
// DO SOMETHING WITH VALUE
}
#endif
Where the string "value" is the value sent from UnitySendMessage
Now I can use this value in Unity3D

Related

How to disable Gameobjects for Screenshot capturing in Unity on Android?

I have a simple goal for my Unity application running on Android: create a function, which disables my GUI, creates a screenshot, stores the image and enables the GUI again.
This is my current code:
The whole UI is stored in a GameObject which my handler class holds as property:
private bool makeScreenshotFlag;
public GameObject UserInterface;
makeScreenshotFlag above is used in the Update function:
// Update is called once per frame
void Update()
{
if (makeScreenshotFlag)
{
// Working with this flag is necessary,
// since we need to wait for the next frame,
// where the gui is not visible;
MakeScreenShot();
}
}
If the corresponding button gets pressed I fire the following Method:
public void OnCreateScreenshotButtonPressed()
{
UserInterface.SetActive(false);
makeScreenshotFlag = true;
}
And at last the method for the screenshot itself:
private void MakeScreenShot()
{
if (UserInterface.activeSelf) return; // wait for the next frame if the gui is still active
try
{
string filename = "screenshot_" + DateTime.Now.ToString("HH-mm-ss--dd-MM-yyyy") + ".png";
ScreenCapture.CaptureScreenshot(filename);
}
catch (Exception e)
{
DebugHelper.NewLog = "Error capturing screenshot: " + e.Message;
}
finally
{
makeScreenshotFlag = false;
UserInterface.SetActive(true);
}
}
In theory this should work, however the documentation for ScreenCapture.CaptureScreenshot() states the following:
The CaptureScreenshot returns immediately on Android. The screen capture continues in the background. The resulting screen shot is saved in the file system after a few seconds.
In practice this means, when my screenshot is made, the GUI is already enabled again. So far I couldn't find any event or similar to get notified as soon as the screenshot is made. The only thing I can think of is to store the screenshot filename and check if the file exists each frame after the screenshot is started.
Is there any other, more practical way?
Most probably, you are capturing the frame with UI itself. It's better to wait till the end of the frame using Coroutine.
public IEnumerator MakeScreenShot()
{
// Wait till the last possible moment before screen rendering to hide the UI
yield return null;
// Disable UI
UserInterface.SetActive(false);
// Wait for screen rendering to complete
yield return new WaitForEndOfFrame();
// Take screenshot
Application.CaptureScreenshot("screenshot.png");
// Show UI after we're done
UserInterface.SetActive(true);
}

how to check if a virtual camera has fully transitioned or not in C#?

I'm working on a C#/Unity project, and I want to know when the cinemachine virtual camera has fully transitioned to another cinemachine camera. I've seen people using IsBlending, but I'm still not sure how to implement that code in my project.
My code is like..
private CinemachineBlend activeBlend = null;
public bool IsBlending { get { return activeBlend != null; } }
[SerializeField] private CinemachineVirtualCamera[] virtualCameras;
void TestItIsWorking()
{
virtualCameras[0].Priority = 10;
virtualCameras[1].Priority = 0; // -> this starts the blending the virtual camera
Debug.Log("this function is called"); // -> prints "this function is called"
Debug.Log(IsBlending); // -> prints false
}
So I guess I'm doing something wrong because event the virtual camera has started to change, I get a false value as of IsBlending boolean. I also wrote while loop instead of just Debug logging the IsBlending value, but the result was still the same. I want to run another function right after the blending has finished, so if there is a better solution for this, please also let me know....
Are you sure your activeBlend field getting a reference correctly? Using the IsBlending property of your CinemachineBrain is an option by the way.

I'm really struggling to pass the Oculus VRC TestSubmitWhenNotVisible test

I'm stuck on the last test for my app before submission to the Oculus store. I've tried all sorts with no avail. I need to do is pass the frames when not visible test.
Effectively, the app needs to go into pause mode when the user clicks the menu button on the oculus touch controller.
I need to stop all frames submitting from Unity. For example, things I've tried, turn off cameras, audio, ovrplayercontroller etc but frames being submitted when the menu button is pressed on the rift so it would appear to freeze the application.
I've tried disabling cameras in a foreach loop, disabling the player gameobject, ovr controllers all sorts.
I have a gameobject with a script attached to try and detect when the test will fire based on the HMD losing tracking.
Here's where I'm currently at (gone back to the basics again), any help would be greatly appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HMDCheck : MonoBehaviour
{
public GameObject OVRCameraRig;
private void Update()
{
if (!OVRManager.isHmdPresent)
{
OVRCameraRig.SetActive(false);
Time.timeScale = 0f;
}
else
{
OVRCameraRig.SetActive(true);
Time.timeScale = 1f;
}
}
}
Additionally their docs say the test performs this action:
TestSubmitFramesWhenNotVisible
Tests if your app stops submitting frames when the Universal Menu is open.
Note :
My most recent command line response for the test is the following output :
Starting TestSubmitFramesWhenNotVisible
Waiting for the application to run for 5 seconds before testing begins...
Starting test...
Requesting the void...
Number of texture swap chains committed when visible 68
Number of texture swap chains committed when not visible 4
ERROR: Committed a texture swap chain (called ovr_CommitTextureSwapChain) when application not visible
Please refer to VRC Guidelines:
https://developer.oculus.com/distribute/latest/concepts/vrc-pc-input-1/
Cleaning up...
Test FAILED
To get around it, I created a script with public gameobjects. I then dragged my player into the slots inside Unity but left the camera on the scene alone. Here's a screenshot and the code. I initially added the camera to turn off frames sending but Oculus rejected it as it froze in the background upon pressing the menu button.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HMDCheck : MonoBehaviour
{
public GameObject target, scripts, LocalAvatar;
private void Update()
{
if (!OVRManager.hasVrFocus || !OVRManager.isHmdPresent || !OVRManager.hasInputFocus)
{
//target.SetActive(false);
scripts.SetActive(false);
LocalAvatar.SetActive(false);
Time.timeScale = 0f;
AudioListener.pause = true;
}
else
{
//target.SetActive(true);
scripts.SetActive(true);
LocalAvatar.SetActive(true);
Time.timeScale = 1f;
AudioListener.pause = false;
}
}
}
I have almost the same code, but this detects the Universal Menu correctly and does freeze the output, but it still won't pass the test. I think it may pass if you disable splash screens, but can't know since I have the free version of Unity.
Edit: I saw your answer Diego, but cannot comment. Did your action resolve your original question? And what license do you have for Unity?
Camera cam;
bool bPause = false;
void Update()
{
//install 'Oculus Integration' for this to work
bool bPauseNow = !(OVRManager.hasInputFocus && OVRManager.hasVrFocus);
//pause state change
if (Camera.main != null) cam = Camera.main;
if (bPause != bPauseNow)
{
bPause = bPauseNow;
if (bPauseNow)
{
Time.timeScale = 0.0f; //stops FixedUpdate
//Update keeps running, but
// rendering must also be paused to pass vrc
cam.enabled = false;
}
else
{
Time.timeScale = 1.0f;
//
cam.enabled = true;
}
}
//...
}
I am using the "Oculus XR Plugin", and got this issue,
but I found that the results of the "VRC Validator" are not so accurate,
then I submitted the App for review and passed the test.

How to run Unity program in background?

I have developed an unity android application. I want to perform some action when app is in foreground and also in background. Right now i am trying to print log in several interval of time in recursive manner. I am using this method to call my countdown timer.
void OnApplicationFocus(bool hasFocus){
StartBattle();
isPaused = !hasFocus;
Debug.Log("isPaused " + isPaused);
}
void OnApplicationPause(bool pauseStatus){
isPaused = pauseStatus;
StartBattle();
}
And this method to print data in a recursive manner.
public void StartBattle(){
StartCoroutine(BattleRecursive(0));
}
public IEnumerator BattleRecursive(int depth){
// Start Coroutine"
yield return new WaitForSeconds(2f);
if (depth == 0)
yield return StartCoroutine(BattleRecursive(depth + 1));
if (depth == 1)
yield return StartCoroutine(BattleRecursive(depth + 1));
Debug.Log("MyCoroutine is now finished at depth " + depth);
}
Log is printing very well when app is in foreground, But when app is in background, it is not printing anything.
You can't execute your Unity C# code in the background when Unity exit. This code you want to run in the background must be made in Java.
Write the code you want to Execute in Java not in C# then use Android's Intent to start a service. This requires that you send current Unity's Context or Activity to your plugin in order to start the service. You can find examples on how to do that here and here.

Programming issue. Lag

Ive been having some issues programming in unity with c#. I am trying to request an interstitial AD when i start the game so i can show it when the player has died 5 times. The issue is that when i get to the 5th death the ad won't show. and when I try requesting the ad when the level starts it gets laggy and still doesn't show.
This is my code. It seems right.
void Update(){
if (clicks >= 5) {
RequestInterstitial();
Debug.Log("Got 5 clicks");
if (interstitial.IsLoaded()){
Debug.Log("interstitial loaded");
interstitial.Show();
clicks = 0;
}
}
}
EDIT: After modifying my code, I now get the error:
NullReferenceException: Object reference not set to an instance of an object ADS.ADMobsGameplay.Update () (at Assets/Scripts/ADS/ADMobsGameplay.cs:28)
Line 28 corresponds to if (interstitial.IsLoaded()){ in the following code:
void Update(){
if (clicks >= 5) {
Debug.Log("Got 5 clicks");
if (interstitial.IsLoaded()){
Debug.Log("interstitial loaded");
interstitial.Show();
clicks = 0;
}else{
RequestInterstitial();
}
}
}
You are Requesting the Interstitial over and over again. Just run the RequestInterstitial method at the beginning of the program (and make sure it only runs the method once).
Then, in whatever method you increment clicks, simply add something like this to the end:
int clicksRequired = 5;
int currentClicksRequired = 5;
if(clicks > currentClicksRequired){
Debug.Log("Got 5 Clicks");
if (interstitial.IsLoaded()){
Debug.Log("interstitial loaded");
interstitial.Show();
RequestInterstitial();
clicks = 0;
currentClicksRequired = clicksRequired;
}else{
Debug.Log("interstitial not loaded, skipping to next click");
currentClickRequired ++;
}
}
Once clicks reaches 5, it will check if the interstitial has been loaded. If so, it shows the interstitial, requests another interstitial, resets clicks at 0, and then moves on. If the interstitial is not loaded yet, it makes you wait till the 6th click, or the 7th, etc, until the interstitial is loaded.
First of all, you shown NullReferenceException error in yours comment: this is first issue that can provide lags. Second - it is really weird to put some counting logic into Update function - update works every frame - so it`s second possible lag issue. Third Debug.Log function is not a lightweight, into Update function it will be third possible lag issue

Categories