Forum Discussion

🚨 This forum is archived and read-only. To submit a forum post, please visit our new Developer Forum. 🚨
harrz-s's avatar
harrz-s
Explorer
5 years ago

SecurityException when accessing Bluetooth API

I'm trying to access the Bluetooth API within a Unity project, but I end up with a SecurityException:
01-24 20:40:47.280 26380 26405 E Unity   : AndroidJavaException: java.lang.SecurityException: Need BLUETOOTH permission: Neither user 10076 nor current process has android.permission.BLUETOOTH.
01-24 20:40:47.280 26380 26405 E Unity : java.lang.SecurityException: Need BLUETOOTH permission: Neither user 10076 nor current process has android.permission.BLUETOOTH.
01-24 20:40:47.280 26380 26405 E Unity : at android.os.Parcel.readException(Parcel.java:1692)
01-24 20:40:47.280 26380 26405 E Unity : at android.os.Parcel.readException(Parcel.java:1645)
01-24 20:40:47.280 26380 26405 E Unity : at android.bluetooth.IBluetooth$Stub$Proxy.isEnabled(IBluetooth.java:864)
01-24 20:40:47.280 26380 26405 E Unity : at android.bluetooth.BluetoothAdapter.isEnabled(BluetoothAdapter.java:622)
01-24 20:40:47.280 26380 26405 E Unity : at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
01-24 20:40:47.280 26380 26405 E Unity : at com.unity3d.player.UnityPlayer.access$300(Unknown Source)
01-24 20:40:47.280 26380 26405 E Unity : at com.unity3d.player.UnityPlayer$e$1.handleMessage(Unknown Source)
01-24 20:40:47.280 26380 26405 E Unity : at android.os.Handler.dispatchMessage(Handler.java:98)
01-24 20:40:47.280 26380 26405 E Unity : at android.os.Looper.loop(Looper.java:154)
01-24 20:40:47.280 26380 26405 E Unity : at com.unity3d.player.UnityPlayer$e.run(Unknown Source)
01-24 20:40:47.280 26380 26405 E Unity : at UnityEngine.AndroidJNISafe.CheckException () [0x0008d] in /Users/bokken/buildslave/unity/build/Modules/AndroidJNI/AndroidJNISafe
However, my AndroidManifest.xml lists all required permissions:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<application android:label="@string/app_name" android:icon="@mipmap/app_icon" android:allowBackup="false">
<activity android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:configChanges="locale|fontScale|keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" android:launchMode="singleTask" android:name="com.unity3d.player.UnityPlayerActivity" android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.INFO" />
</intent-filter>
<meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
</activity>
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="false" />
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only" />
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2" />
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
</manifest>
This is my simple test script which also asks for the FINE_LOCATION permission if necessary:
    void Start() {
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation)) {
Permission.RequestUserPermission(Permission.FineLocation);
} else {
AndroidJavaClass bluetooth = new AndroidJavaClass("android.bluetooth.BluetoothAdapter");
AndroidJavaObject bluetoothAdapter = bluetooth.CallStatic<AndroidJavaObject>("getDefaultAdapter");

if (!bluetoothAdapter.Call<bool>("isEnabled")) {
bluetoothAdapter.Call<bool>("enable");
}

AndroidJavaObject mBluetoothLeScanner = bluetoothAdapter.Call<AndroidJavaObject>("getBluetoothLeScanner");
ScanCallback scanCallback = new ScanCallback();

mBluetoothLeScanner.Call("startScan", scanCallback);
}
}

Does anyone have success with accessing Bluetooth on the Quest from within a Unity project?

13 Replies

  • Hi, I had no such issue for Quest I used the Arduino Bluetooth Plugin from the asset store but I am unable to search any devices in Quest2. 
  • First of all, I could finally identify the problem by exporting the Gradle project via File - Build Settings... and selecting Export Project. In the resulting project folder, when I navigated to unityLibrary\src\main and opened up AndroidManifest.xml, I could see that the permission android.permission.BLUETOOTH had been stripped out, which explains the error message.

    After a lot of testing around, it seems that I had some sort of strange interaction between the Oculus Integration Asset and the new Unity XR Plugin Management together with the Oculus XR Plugin. The error did not occur with version 1.4.3 of the Oculus XR Plugin, but with any higher version.

    I wanted to compile a sample project and open a bug report, but now I cannot reproduce the error anymore. Let's see whether the bug decides to come back at some point.
  • I followed these instructions and downgraded to 1.4.3 however the Bluetooth permission is still being stripped out. I can't figure out how to work around this...
  • Does anyone have a working Bluetooth example on Github they can share?  I bought two of the plugins but neither work probably due to permissions issues.

  • I don't know how to prevent the BLUETOOTH permission being stripped, however a solution is to export an Android project and then manually add in <uses-permission android:name="android.permission.BLUETOOTH"/> 

    You can then use Android Studio to build the APK and deploy

  • You can modify the Packages/Oculus XR Plugin/Editor/OculusBuildProcesor.cs script, commenting the line #434, which is the culprit in this case.

    • oculus-papa's avatar
      oculus-papa
      Explorer

      Thank you. My workaround: I have been exporting the project and building in Android Studio. 

    • harrz-s's avatar
      harrz-s
      Explorer

      Yeah, just found that out as well. However, your change might get overwritten when you update the package.

       

      You can use the following script, which will re-add the bluetooth permission to the manifest. Just put it into a folder called "Editor", then it will run after the OculusBuildProcessor:

      using System.Xml;
      using UnityEditor;
      using UnityEditor.Android;
      using UnityEditor.XR.Oculus;
      
      #if UNITY_ANDROID
      internal class OculusManifestBTFixer : IPostGenerateGradleAndroidProject {
          static readonly string k_AndroidURI = "http://schemas.android.com/apk/res/android";
          static readonly string k_AndroidManifestPath = "/src/main/AndroidManifest.xml";
      
          void CreateNameValueElementsInTag(XmlDocument doc, string parentPath, string tag,
              string firstName, string firstValue, string secondName = null, string secondValue = null, string thirdName = null, string thirdValue = null) {
              var xmlNodeList = doc.SelectNodes(parentPath + "/" + tag);
      
              // don't create if the firstValue matches
              foreach (XmlNode node in xmlNodeList) {
                  foreach (XmlAttribute attrib in node.Attributes) {
                      if (attrib.Value == firstValue) {
                          return;
                      }
                  }
              }
      
              XmlElement childElement = doc.CreateElement(tag);
              childElement.SetAttribute(firstName, k_AndroidURI, firstValue);
      
              if (secondValue != null) {
                  childElement.SetAttribute(secondName, k_AndroidURI, secondValue);
              }
      
              if (thirdValue != null) {
                  childElement.SetAttribute(thirdName, k_AndroidURI, thirdValue);
              }
      
              var xmlParentNode = doc.SelectSingleNode(parentPath);
      
              if (xmlParentNode != null) {
                  xmlParentNode.AppendChild(childElement);
              }
          }
      
          public void OnPostGenerateGradleAndroidProject(string path) {
              if (!OculusBuildTools.OculusLoaderPresentInSettingsForBuildTarget(BuildTargetGroup.Android))
                  return;
      
              var manifestPath = path + k_AndroidManifestPath;
              var manifestDoc = new XmlDocument();
              manifestDoc.Load(manifestPath);
      
              string nodePath = "/manifest";
              CreateNameValueElementsInTag(manifestDoc, nodePath, "uses-permission", "name", "android.permission.BLUETOOTH");
      
              manifestDoc.Save(manifestPath);
          }
      
          public int callbackOrder { get { return 20000; } }
      }
      #endif
      • tgaze's avatar
        tgaze
        Explorer

        Hello harrz-s,

        I am also running into this problem. Could you please explain where I need to put this file and what to name it? 

        Thank you,

        tgaze

    • PawSix's avatar
      PawSix
      Explorer

      Thanks for the tip! Makes sense, though Unity reverts any changes I make to that script so I had to resort to another method described in another reply in this thread.