如何在仪器中注册广播接收器?

How to register broadcast receiver inside instrumentation?

我正在尝试通过作为 android junit runner 运行的 apk 获取蓝牙发现结果。一切正常,但在 registerReciever 时出现以下错误。可能是什么原因?

java.lang.SecurityException: Given caller package com.ex.test is not running in process ProcessRecord{d740580 19462:com.ex/u0a302}

代码-

@Test
public void demo() throws Exception {

    Context ctx = InstrumentationRegistry.getInstrumentation().getContext();
    BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();

    if (mBtAdapter.isDiscovering()) {
        System.out.println("Stop ongoing discovery");
        mBtAdapter.cancelDiscovery();
    }
    System.out.println("Start fresh discovery");
    mBtAdapter.startDiscovery();

    DisciveryRecv dReceiver = new DisciveryRecv ();
    // Register for broadcasts when a device is discovered
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    ctx.registerReceiver(dReceiver, filter);
}


public class DisciveryRecv extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction(); 
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String dev = device.getName() + " - " + device.getAddress();
            mUtils.log("Found: " + dev);
        }
    }
}

startDiscovery 工作正常,但在 ctx.registerReceiver(dReceiver, filter); 时,应用程序抛出异常。

检测命令-

adb shell am instrument -w -r -e debug false -e class com.ex.main#demo com.ex/android.support.test.runner.AndroidJUnitRunner

我自己找到了答案。使用 InstrumentationRegistry.getTargetContext() 解决了我的问题。

InstrumentationRegistry.getInstrumentation(), returns the Instrumentation currently running.

InstrumentationRegistry.getContext(), returns the Context of this Instrumentation’s package.

InstrumentationRegistry.getTargetContext(), returns the application Context of the target application.

这里有一些信息- https://developer.android.com/reference/android/support/test/InstrumentationRegistry.html#getTargetContext()

但我仍然不确定何时使用 InstrumentationRegistry.getContext()...

InstrumentationRegistry.getTargetContext() returns 正在测试的应用程序的上下文。

InstrumentationRegistry.getContext() returns 检测的上下文 运行 测试。

然后,如果你想像你描述的那样注册一个接收器,你需要你的应用程序上下文。但是,这并不是真正测试您的应用程序接收广播,因为接收器不是您的应用程序的一部分。

无论如何,在回答您的第二个问题时,使用 InstrumentationRegistry.getContext() 的原因是当您的测试需要访问不属于应用程序但仅在测试中使用的资源或文件时。

编辑

这里有一个例子。两个文件,一个在应用程序中,另一个在测试中

src/androidTest/assets/sometestfile
src/main/assets/someappfile

然后您可以根据上下文访问它们

@Test
public final void testAccessToAppAssetsFromTest() throws IOException {
    final AssetManager assetManager = mInstrumentation.getTargetContext().getAssets();
    assetManager.open("someappfile");
}

@Test
public final void testAccessToTestAssetsFromTest() throws IOException {
    final AssetManager assetManager = mInstrumentation.getContext().getAssets();
    assetManager.open("sometestfile");
}

如果您尝试相反的操作,测试将失败。