cancel
Showing results for 
Search instead for 
Did you mean: 

SecurityException when accessing Bluetooth API

harrz-s
Explorer
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 13

NitinTiwari
Explorer
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. 

harrz-s
Explorer
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.

vartech
Explorer
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...

oculus-papa
Explorer

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.

jamesar
Explorer

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

andriuspa
Honored Guest

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

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

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

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