Enable bluetooth tethering android programmaticall

2020-02-10 07:13发布

问题:

I am trying to make an application like "Bluetooth auto tethering" on play store. I read on the forum that Android is very security-aware and will not enable this setting without user interaction.

I need some explanations about how enable bluetooth tethering.

Thank you

回答1:

I don't know if this is still an issue or not, but I found that using the connect method in the reflection call works. Working off of the code that pmont used from the link in Lorelorelore's answer:

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Class<?> classBluetoothPan = null;
Constructor<?> BTPanCtor = null;
Object BTSrvInstance = null;
Method mBTPanConnect;

try {
    classBluetoothPan = Class.forName("android.bluetooth.BluetoothPan");
    mBTPanConnect = classBluetoothPan.getDeclaredMethod("connect", BluetoothDevice.class);
    BTPanCtor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
    BTPanCtor.setAccessible(true);
    BTSrvInstance = BTPanCtor.newInstance(myContext, new BTPanServiceListener(myContext));
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        try{
            mBTPanConnect.invoke(BTSrvInstance, device);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Of course, this assumes that the bluetooth is enabled, and you only have one paired device. But enabling bluetooth is pretty straightforward using standard (not reflection) calls, and you can just check for the paired device that you want to connect to in the for loop. Also, don't forget the BTPanServiceListener class from the other answer as well.

Hope this helps.



回答2:

The solution above required some modification in order to work for me. Specifically, the code to enable tethering needs to be in the OnServiceConnected() method. Also I have the following permissions set in the manifest:

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

Here is my solution:

public class BluetoothTethering extends ActionBarActivity {

    Object instance = null;
    Method setTetheringOn = null;
    Method isTetheringOn = null;
    Object mutex = new Object();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bluetooth_tethering);
        String sClassName = "android.bluetooth.BluetoothPan";

        try {

            Class<?> classBluetoothPan = Class.forName(sClassName);

            Constructor<?> ctor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
            ctor.setAccessible(true);
            //  Set Tethering ON
            Class[] paramSet = new Class[1];
            paramSet[0] = boolean.class;

            synchronized (mutex) {
                setTetheringOn = classBluetoothPan.getDeclaredMethod("setBluetoothTethering", paramSet);
                isTetheringOn = classBluetoothPan.getDeclaredMethod("isTetheringOn", null);
                instance = ctor.newInstance(getApplicationContext(), new BTPanServiceListener(getApplicationContext()));
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class BTPanServiceListener implements BluetoothProfile.ServiceListener {

        private final Context context;

        public BTPanServiceListener(final Context context) {
            this.context = context;
        }

        @Override
        public void onServiceConnected(final int profile,
                                       final BluetoothProfile proxy) {
            //Some code must be here or the compiler will optimize away this callback.

            try {
                synchronized (mutex) {
                    setTetheringOn.invoke(instance, true);
                    if ((Boolean)isTetheringOn.invoke(instance, null)) {
                        Toast.makeText(getApplicationContext(), "BT Tethering is on", Toast.LENGTH_LONG).show();
                    }
                    else {
                        Toast.makeText(getApplicationContext(), "BT Tethering is off", Toast.LENGTH_LONG).show();
                    }
                }
            }
            catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(final int profile) {
        }
    }
}


回答3:

The below code works perfectly for me

String sClassName = "android.bluetooth.BluetoothPan";

try {  

    Class<?> classBluetoothPan = Class.forName(sClassName);

    Constructor<?> ctor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
    ctor.setAccessible(true);
    Object instance = ctor.newInstance(getApplicationContext(), new BTPanServiceListener(getApplicationContext()));                 
    //  Set Tethering ON
    Class[] paramSet = new Class[1];
    paramSet[0] = boolean.class;

    Method setTetheringOn = classBluetoothPan.getDeclaredMethod("setBluetoothTethering", paramSet);

    setTetheringOn.invoke(instance,true);

} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

public class BTPanServiceListener implements BluetoothProfile.ServiceListener {

    private final Context context;

    public BTPanServiceListener(final Context context) {
        this.context = context;
    }

    @Override
    public void onServiceConnected(final int profile,
            final BluetoothProfile proxy) {
        //Some code must be here or the compiler will optimize away this callback.
        Log.e("MyApp", "BTPan proxy connected");

    }

    @Override
    public void onServiceDisconnected(final int profile) {
    }
}


回答4:

Here you find a similar question: Bluetooth question

Just replace "isTetheringOn" with "setBluetoothTethering" in the reflection call and pass in a boolean parameter. It should work.