最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Android Development with Unity, unable to get compass sensor output - Stack Overflow

programmeradmin0浏览0评论

The code I have for a compass feature works when I execute the app using the Unity Remote application connected via USB to the PC. However, if I build an APK, it behaves differently; in fact, it does nothing.

App that I mean: enter image description here My app executing... and it is working as expected enter image description here

But if I build the apk, when I run it, it ask me for location permission. enter image description here

However, it does nothing, and for some reason, it says that what I originally declared as enabled in the Start function in Unity is stopped when I check it in the Update function. enter image description here

And this would be the code:

using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;

public class Compass_Behaviour : MonoBehaviour
{   
    
    [SerializeField] Transform Compass;
    [SerializeField] Text Text01;
    [SerializeField] Text Text02;
    [SerializeField] Text Text03;
    [SerializeField] Text Text04;
    [SerializeField] Text Text05;    

    [SerializeField] float currentHeading;
    [SerializeField] float storedHeading = 0f;

    void Start()
    {
        Text01.text = "Check Location Approval";
        Text02.text = "Check Location.Status";
        Text03.text = "Check if Compass Stopped";
        Text04.text = "Check currentHeading";
        Text05.text = "Check StoredHeading";

        Permission.RequestUserPermission(Permission.FineLocation);
        Invoke("_LocationAskPermission", 1f);

        Input.location.Start();
        Inputpass.enabled = true;
    }
    void _LocationAskPermission()
    {
        if (Permission.HasUserAuthorizedPermission(Permission.FineLocation))Text01.text = "FineLocation Approved";
        else
            Text01.text = "FineLocation Denied";
    }
    void Update()
    {
        if(Input.location.status == LocationServiceStatus.Stopped || !Input.location.isEnabledByUser)
        {
            Text02.text = "location.status stopped";
            Input.location.Start();
        }
        if(!Inputpass.enabled)
        {
            Text03.text = "Compass.enable stopped";
            Inputpass.enabled = true;
        }
        currentHeading = Inputpass.trueHeading;
        Text04.text = "currentHeading: " + currentHeading.ToString();
         
        if (currentHeading != storedHeading)
        {
            if (currentHeading > storedHeading+5 || currentHeading < storedHeading-5)
            {
                Compass.rotation = Quaternion.Euler(0f, -currentHeading, 0f);
                storedHeading = currentHeading;
            }
            Text05.text = "storedHeading: " + storedHeading.ToString();
        }
    }
}

I am not quite sure why the code works or doesn’t in different scenarios, but I think it has something to do with the manifest.xml file that Unity creates. I have been experimenting with it.

This was created by Unity as a temporary file; however, I copied it and made it permanent. The key feature, I guess, is the "<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />".

The part that says uses-feature is only to verify if a device is capable of executing the required hardware. This ensures the app works if it depends on that hardware.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=";
    package="com.UnityTechnologies.Mobile3DTemplate"
    android:installLocation="preferExternal"
    android:versionCode="1"
    android:versionName="1.0.2" >

  <uses-sdk
      android:minSdkVersion="29"
      android:targetSdkVersion="35" />

  <supports-screens
      android:anyDensity="true"
      android:largeScreens="true"
      android:normalScreens="true"
      android:smallScreens="true"
      android:xlargeScreens="true" />

  <supports-gl-texture android:name="GL_EXT_texture_compression_dxt1" />
  <supports-gl-texture android:name="GL_EXT_texture_compression_dxt5" />
  <supports-gl-texture android:name="GL_EXT_texture_compression_s3tc" />

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


  <uses-feature android:glEsVersion="0x00030000" />
  <uses-feature
      android:name="android.hardware.vulkan.version"
      android:required="false" />
  <uses-feature
      android:name="android.hardware.location.gps"
      android:required="false" />

  <uses-feature
      android:name="android.hardware.touchscreen.multitouch.distinct"
      android:required="false" />

  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

  <permission
      android:name="com.UnityTechnologies.Mobile3DTemplate.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
      android:protectionLevel="signature" />

  <uses-permission android:name="com.UnityTechnologies.Mobile3DTemplate.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" />

  <application
      android:appCategory="game"
      android:appComponentFactory="androidx.core.app.CoreComponentFactory"
      android:enableOnBackInvokedCallback="false"
      android:extractNativeLibs="true"
      android:icon="@mipmap/app_icon"
      android:label="@string/app_name" >
    <meta-data
        android:name="unity.splash-mode"
        android:value="0" />
    <meta-data
        android:name="unity.splash-enable"
        android:value="True" />
    <meta-data
        android:name="unity.launch-fullscreen"
        android:value="True" />
    <meta-data
        android:name="unity.render-outside-safearea"
        android:value="True" />
    <meta-data
        android:name="notch.config"
        android:value="portrait|landscape" />
    <meta-data
        android:name="unity.auto-report-fully-drawn"
        android:value="true" />
    <meta-data
        android:name="unity.auto-set-game-state"
        android:value="true" />
    <meta-data
        android:name="unity.strip-engine-code"
        android:value="false" />
    <meta-data
        android:name="android.game_mode_config"
        android:resource="@xml/game_mode_config" />

    <activity
        android:name="com.unity3d.player.UnityPlayerGameActivity"
        android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
        android:enabled="true"
        android:exported="true"
        android:hardwareAccelerated="false"
        android:launchMode="singleTask"
        android:resizeableActivity="true"
        android:screenOrientation="fullUser"
        android:theme="@style/BaseUnityGameActivityTheme" >
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />

        <action android:name="android.intent.action.MAIN" />
      </intent-filter>

      <meta-data
          android:name="unityplayer.UnityActivity"
          android:value="true" />
      <meta-data
          android:name="android.app.lib_name"
          android:value="game" />
      <meta-data
          android:name="WindowManagerPreference:FreeformWindowSize"
          android:value="@string/FreeformWindowSize_maximize" />
      <meta-data
          android:name="WindowManagerPreference:FreeformWindowOrientation"
          android:value="@string/FreeformWindowOrientation_landscape" />
      <meta-data
          android:name="notch_support"
          android:value="true" />
    </activity>

    <receiver
        android:name="com.unity.androidnotifications.UnityNotificationManager"
        android:exported="false" />
    <receiver
        android:name="com.unity.androidnotifications.UnityNotificationRestartReceiver"
        android:enabled="false"
        android:exported="false" >
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
      </intent-filter>
    </receiver>

    <meta-data
        android:name="com.unity.androidnotifications.exact_scheduling"
        android:value="0" />

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="com.UnityTechnologies.Mobile3DTemplate.androidx-startup"
        android:exported="false" >
      <meta-data
          android:name="androidx.emoji2.text.EmojiCompatInitializer"
          android:value="androidx.startup" />
      <meta-data
          android:name="androidx.lifecycle.ProcessLifecycleInitializer"
          android:value="androidx.startup" />
    </provider>
  </application>

</manifest>

The code I have for a compass feature works when I execute the app using the Unity Remote application connected via USB to the PC. However, if I build an APK, it behaves differently; in fact, it does nothing.

App that I mean: enter image description here My app executing... and it is working as expected enter image description here

But if I build the apk, when I run it, it ask me for location permission. enter image description here

However, it does nothing, and for some reason, it says that what I originally declared as enabled in the Start function in Unity is stopped when I check it in the Update function. enter image description here

And this would be the code:

using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;

public class Compass_Behaviour : MonoBehaviour
{   
    
    [SerializeField] Transform Compass;
    [SerializeField] Text Text01;
    [SerializeField] Text Text02;
    [SerializeField] Text Text03;
    [SerializeField] Text Text04;
    [SerializeField] Text Text05;    

    [SerializeField] float currentHeading;
    [SerializeField] float storedHeading = 0f;

    void Start()
    {
        Text01.text = "Check Location Approval";
        Text02.text = "Check Location.Status";
        Text03.text = "Check if Compass Stopped";
        Text04.text = "Check currentHeading";
        Text05.text = "Check StoredHeading";

        Permission.RequestUserPermission(Permission.FineLocation);
        Invoke("_LocationAskPermission", 1f);

        Input.location.Start();
        Inputpass.enabled = true;
    }
    void _LocationAskPermission()
    {
        if (Permission.HasUserAuthorizedPermission(Permission.FineLocation))Text01.text = "FineLocation Approved";
        else
            Text01.text = "FineLocation Denied";
    }
    void Update()
    {
        if(Input.location.status == LocationServiceStatus.Stopped || !Input.location.isEnabledByUser)
        {
            Text02.text = "location.status stopped";
            Input.location.Start();
        }
        if(!Inputpass.enabled)
        {
            Text03.text = "Compass.enable stopped";
            Inputpass.enabled = true;
        }
        currentHeading = Inputpass.trueHeading;
        Text04.text = "currentHeading: " + currentHeading.ToString();
         
        if (currentHeading != storedHeading)
        {
            if (currentHeading > storedHeading+5 || currentHeading < storedHeading-5)
            {
                Compass.rotation = Quaternion.Euler(0f, -currentHeading, 0f);
                storedHeading = currentHeading;
            }
            Text05.text = "storedHeading: " + storedHeading.ToString();
        }
    }
}

I am not quite sure why the code works or doesn’t in different scenarios, but I think it has something to do with the manifest.xml file that Unity creates. I have been experimenting with it.

This was created by Unity as a temporary file; however, I copied it and made it permanent. The key feature, I guess, is the "<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />".

The part that says uses-feature is only to verify if a device is capable of executing the required hardware. This ensures the app works if it depends on that hardware.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android/apk/res/android"
    package="com.UnityTechnologies.Mobile3DTemplate"
    android:installLocation="preferExternal"
    android:versionCode="1"
    android:versionName="1.0.2" >

  <uses-sdk
      android:minSdkVersion="29"
      android:targetSdkVersion="35" />

  <supports-screens
      android:anyDensity="true"
      android:largeScreens="true"
      android:normalScreens="true"
      android:smallScreens="true"
      android:xlargeScreens="true" />

  <supports-gl-texture android:name="GL_EXT_texture_compression_dxt1" />
  <supports-gl-texture android:name="GL_EXT_texture_compression_dxt5" />
  <supports-gl-texture android:name="GL_EXT_texture_compression_s3tc" />

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


  <uses-feature android:glEsVersion="0x00030000" />
  <uses-feature
      android:name="android.hardware.vulkan.version"
      android:required="false" />
  <uses-feature
      android:name="android.hardware.location.gps"
      android:required="false" />

  <uses-feature
      android:name="android.hardware.touchscreen.multitouch.distinct"
      android:required="false" />

  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

  <permission
      android:name="com.UnityTechnologies.Mobile3DTemplate.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
      android:protectionLevel="signature" />

  <uses-permission android:name="com.UnityTechnologies.Mobile3DTemplate.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" />

  <application
      android:appCategory="game"
      android:appComponentFactory="androidx.core.app.CoreComponentFactory"
      android:enableOnBackInvokedCallback="false"
      android:extractNativeLibs="true"
      android:icon="@mipmap/app_icon"
      android:label="@string/app_name" >
    <meta-data
        android:name="unity.splash-mode"
        android:value="0" />
    <meta-data
        android:name="unity.splash-enable"
        android:value="True" />
    <meta-data
        android:name="unity.launch-fullscreen"
        android:value="True" />
    <meta-data
        android:name="unity.render-outside-safearea"
        android:value="True" />
    <meta-data
        android:name="notch.config"
        android:value="portrait|landscape" />
    <meta-data
        android:name="unity.auto-report-fully-drawn"
        android:value="true" />
    <meta-data
        android:name="unity.auto-set-game-state"
        android:value="true" />
    <meta-data
        android:name="unity.strip-engine-code"
        android:value="false" />
    <meta-data
        android:name="android.game_mode_config"
        android:resource="@xml/game_mode_config" />

    <activity
        android:name="com.unity3d.player.UnityPlayerGameActivity"
        android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
        android:enabled="true"
        android:exported="true"
        android:hardwareAccelerated="false"
        android:launchMode="singleTask"
        android:resizeableActivity="true"
        android:screenOrientation="fullUser"
        android:theme="@style/BaseUnityGameActivityTheme" >
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />

        <action android:name="android.intent.action.MAIN" />
      </intent-filter>

      <meta-data
          android:name="unityplayer.UnityActivity"
          android:value="true" />
      <meta-data
          android:name="android.app.lib_name"
          android:value="game" />
      <meta-data
          android:name="WindowManagerPreference:FreeformWindowSize"
          android:value="@string/FreeformWindowSize_maximize" />
      <meta-data
          android:name="WindowManagerPreference:FreeformWindowOrientation"
          android:value="@string/FreeformWindowOrientation_landscape" />
      <meta-data
          android:name="notch_support"
          android:value="true" />
    </activity>

    <receiver
        android:name="com.unity.androidnotifications.UnityNotificationManager"
        android:exported="false" />
    <receiver
        android:name="com.unity.androidnotifications.UnityNotificationRestartReceiver"
        android:enabled="false"
        android:exported="false" >
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
      </intent-filter>
    </receiver>

    <meta-data
        android:name="com.unity.androidnotifications.exact_scheduling"
        android:value="0" />

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="com.UnityTechnologies.Mobile3DTemplate.androidx-startup"
        android:exported="false" >
      <meta-data
          android:name="androidx.emoji2.text.EmojiCompatInitializer"
          android:value="androidx.startup" />
      <meta-data
          android:name="androidx.lifecycle.ProcessLifecycleInitializer"
          android:value="androidx.startup" />
    </provider>
  </application>

</manifest>
Share Improve this question asked Nov 20, 2024 at 3:52 Miguel Alexander Vasquez OrtegMiguel Alexander Vasquez Orteg 1
Add a comment  | 

1 Answer 1

Reset to default 0

You're checking if user has permission immediately (1s) after Requesting for permission, try a Coroutine instead of invocation

Example code

Permission.RequestUserPermission(Permission.FineLocation);
Invoke("_LocationAskPermission", 1f); // Change to StartCoroutine(WaitForPermissionRoutine())

private IEnumerator WaitForPermissionRoutine() 
{
    var timeOut = 10;
    bool hasPermission = Permission.HasUserAuthorizedPermission(Permission.FineLocation);
    while (timeOut > 0 || hasPermission)
    {
         hasPermission = Permission.HasUserAuthorizedPermission(Permission.FineLocation);
         timeOut -= Time.deltaTime;
         yield return null;
    }
    
    // Additional checks...
    if (!hasPermission))
    {
        // log error
        yield break;
    }

    Input.location.Start();
    Inputpass.enabled = true;

    // ...
}
发布评论

评论列表(0)

  1. 暂无评论