【问题标题】:How to detect if android device is paired with android wear watch如何检测安卓设备是否与安卓手表配对
【发布时间】:2014-07-22 00:46:37
【问题描述】:

我正在创建一个扩展推送通知的 Android Wear 应用程序。当推送通知进来时,我的应用程序会从服务器下载大约 10 张图像,并在手表上显示这些额外的图像。这些图像特定于 android wear 应用,不会显示在手持设备上。

如何判断手持设备是否与安卓穿戴设备配对,以便确定是否需要下载穿戴应用所需的额外图片?

谢谢!

【问题讨论】:

  • 我只是检查是否安装了 Android Wear,然后下载这些资产。如果安装了 Android Wear,但没有配对手表,那么它很有可能在未来配对。
  • @323go 怎么判断是否安装了android wear?
  • 像所有其他应用一样通过PackageManager
  • 以下是如何检查的完整示例:stackoverflow.com/a/39513489/878126

标签: android wear-os


【解决方案1】:

这里已经列出了 2 个选项。它们都有效,具体取决于您的用例。我想添加第三个选项,但不完整。

选项 1:使用 NodeApi 查找连接的节点

NodeApi 类有一个检索连接节点的方法。有了这个,您就可以确定用户过去不只是拥有一只手表或曾经测试过一只手表。他真的在附近有一块手表并且已经连接了。

这种方法的缺点是,如果没有启用蓝牙或此时手表未连接,您将无法获得任何结果。

方法是:

List<Node> connectedNodes =
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await().getNodes();

更完整的代码示例如下所示:

private GoogleApiClient client;
private static final long CONNECTION_TIME_OUT_MS = 1000;

public void checkIfWearableConnected() {

    retrieveDeviceNode(new Callback() {
        @Override
        public void success(String nodeId) {
            Toast.makeText(this, "There was at least one wearable found", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void failed(String message) {
            Toast.makeText(this, "There are no wearables found", Toast.LENGTH_SHORT).show();
        }
    });

}

private GoogleApiClient getGoogleApiClient(Context context) {
        if (client == null)
            client = new GoogleApiClient.Builder(context)
                    .addApi(Wearable.API)
                    .build();
        return client;
    }

private interface Callback {
        public void success(final String nodeId);
        public void failed(final String message);
    }

private void retrieveDeviceNode(final Callback callback) {
        final GoogleApiClient client = getGoogleApiClient(this);
        new Thread(new Runnable() {

            @Override
            public void run() {
                client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
                NodeApi.GetConnectedNodesResult result =
                        Wearable.NodeApi.getConnectedNodes(client).await();
                List<Node> nodes = result.getNodes();
                if (nodes.size() > 0) {
                    String nodeId = nodes.get(0).getId();
                    callback.success(nodeId);
                } else {
                    callback.failed("no wearables found");
                }
                client.disconnect();
            }
        }).start();
    }

选项 2:检查 Android Wear 应用

这就是第二种选择的优势。如果您拿到手表,首先要连接它,就是在您的掌上电脑上安装 Android Wear 应用程序。因此,您可以使用PackageManager 来验证是否安装了此 Android Wear 应用程序。

这里的缺点是您可以在没有手表的情况下安装 Wear 应用。

代码示例:

try {
    getPackageManager().getPackageInfo("com.google.android.wearable.app", PackageManager.GET_META_DATA);

    Toast.makeText(this, "The Android Wear App is installed", Toast.LENGTH_SHORT).show();
} catch (PackageManager.NameNotFoundException e) {
    //android wear app is not installed
    Toast.makeText(this, "The Android Wear App is NOT installed", Toast.LENGTH_SHORT).show();
}

选项 3:检查配对设备

不确定这是否可行,但在某些情况下,这将是完美的解决方案,因为您可以检查用户的手表是否与他的设备配对,而当时无需连接。

下面是一个代码示例,但这不包括检查配对设备是否为可穿戴设备。这只是一个起点。

代码示例来自:getbondeddevices() not returning paired bluetooth devices

BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();

Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
     Toast.makeText(this, "At least one paired bluetooth device found", Toast.LENGTH_SHORT).show();
    // TODO at this point you'd have to iterate these devices and check if any of them is a wearable (HOW?)
    for (BluetoothDevice device : pairedDevices) {
        Log.d("YOUR_TAG", "Paired device: "+ device.getName() + ", with address: " + device.getAddress());
    }
} else {
    Toast.makeText(this, "No paired bluetooth devices found", Toast.LENGTH_SHORT).show();
}

请注意,此代码需要清单中的蓝牙权限。

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

【讨论】:

  • 选项 4 :问谷歌他们让这很难检测到吗?
  • 选项 3 是 TWilly 正在寻找的,我猜。所以这应该是“公认的答案”。
  • "这种方法的缺点是,如果没有开启蓝牙或者此时手表没有连接,你将得不到任何结果。" - 为什么是缺点?这不是你真正需要的吗?检查智能手表是否真的连接?在什么情况下使用是错误的?
  • @androiddeveloper 真的,这真的取决于你的用例
  • “选项 2:检查 Android Wear 应用程序”不考虑任何使用 com.samsung.android.app.watchmanager 的 Samsung Gear 设备。
【解决方案2】:

您需要使用NodeApi,尤其是NodeApi.getConnectedNodes()

例如(来自后台线程——否则使用setResultCallback() 而不是await()):

List<Node> connectedNodes =
    Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await().getNodes();

如果返回的节点列表包含至少一个元素,则说明存在已连接的 Android Wear 设备,否则不存在。


更新:随着Google Play Services 7.3 的发布,增加了对同时连接多个Android Wear 设备的支持。您可以使用CapabilityApi 请求具有特定功能的节点。

【讨论】:

  • 目前,会不会有多个节点?
  • @schwiz 我不确定,我想如果你能够配对多个设备,那么会有多个节点(?)但是我没有测试过这个,因为我只有一。 :)
  • 您目前不能连接多个设备。当我用 G Watch 替换设计不佳的 Gear Live 时,我学到了这一点。
  • Google Glass 算作一个节点,因此您可以同时连接 Wear 设备和 Glass。
  • "getConnectedNodes" 检测连接节点,而不是配对节点,是吗?
【解决方案3】:

如果手持设备仅连接 Android Watch,以上所有答案都是正确的。如果手持设备连接到多个设备(可穿戴设备),如 Android Watch、HealthBand、Beacon 等,那么上述答案可能不起作用。

以下部分向您展示如何通告可以处理活动请求的设备节点、发现能够满足请求需求的节点以及向这些节点发送消息,

广告功能

要从可穿戴设备在手持设备上启动活动,请使用 MessageApi 类发送请求。由于可以将多个可穿戴设备连接到手持设备,因此可穿戴应用程序需要确定连接的节点能够启动活动。在您的手持应用中,宣传它运行的节点提供特定功能。

宣传您的手持应用程序的功能:

  1. 在项目的 res/values/ 目录中创建一个 XML 配置文件,并将其命名为 wear.xml。
  2. 将名为 android_wear_capabilities 的资源添加到 wear.xml。
  3. 定义设备提供的功能。

<resources>
    <string-array name="android_wear_capabilities">
        <item>android_wear</item>
    </string-array> 
</resources>

检索具有所需功能的节点

最初,您可以通过调用 CapabilityApi.getCapability() 方法来检测有能力的节点。以下示例显示了如何使用 android_wear 功能手动检索可达节点的结果。在 Wear 模块中使用以下代码:

public abstract class BaseActivity extends Activity implements MessageApi.MessageListener, NodeApi.NodeListener,
    DataApi.DataListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private static final String
        SMART_WEAR_CAPABILITY_NAME = "android_wear";

protected GoogleApiClient mGoogleApiClient;
protected ArrayList<String> results;
private String TAG = "BaseActivity::Wear";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

private Collection<String> getNodes() {
    results = new ArrayList<>();
    NodeApi.GetConnectedNodesResult nodes =
            Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();

    for (Node node : nodes.getNodes()) {
        Log.d(TAG, node.getId());
        results.add(node.getId());
    }

    return results;
}

@Override
protected void onResume() {
    super.onResume();
    mGoogleApiClient.connect();
}

@Override
protected void onPause() {
    super.onPause();
    Wearable.MessageApi.removeListener(mGoogleApiClient, this);
    Wearable.NodeApi.removeListener(mGoogleApiClient, this);
    Wearable.DataApi.removeListener(mGoogleApiClient, this);
    mGoogleApiClient.disconnect();
}

@Override
public void onConnected(Bundle bundle) {
    Log.d(TAG, "onConnected(): Successfully connected to Google API client");
    Wearable.MessageApi.addListener(mGoogleApiClient, this);
    Wearable.DataApi.addListener(mGoogleApiClient, this);
    Wearable.NodeApi.addListener(mGoogleApiClient, this);
    results = new ArrayList<>();

    getNodeIdOfHandheldDevice();
}

@Override
public void onConnectionSuspended(int i) {
    Log.d(TAG, "onConnectionSuspended(): Connection to Google API client was suspended");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Log.e(TAG, "onConnectionFailed(): Failed to connect, with result: " + connectionResult);
}

@Override
public void onPeerConnected(Node node) {
    Log.e(TAG, "onPeerConnected():");
}

@Override
public void onPeerDisconnected(Node node) {
    Log.e(TAG, "onPeerDisconnected():");
}

private void getNodeIdOfHandheldDevice() {
    Wearable.CapabilityApi.getCapability(
            mGoogleApiClient, SMART_WEAR_CAPABILITY_NAME,
            CapabilityApi.FILTER_REACHABLE).setResultCallback(
            new ResultCallback<CapabilityApi.GetCapabilityResult>() {
                @Override
                public void onResult(CapabilityApi.GetCapabilityResult result) {
                    if (result.getStatus().isSuccess()) {
                        updateFindMeCapability(result.getCapability());
                    } else {
                        Log.e(TAG,
                                "setOrUpdateNotification() Failed to get capabilities, "
                                        + "status: "
                                        + result.getStatus().getStatusMessage());
                    }
                }
            });
}

private void updateFindMeCapability(CapabilityInfo capabilityInfo) {
    Set<Node> connectedNodes = capabilityInfo.getNodes();
    if (connectedNodes.isEmpty()) {
        results.clear();
    } else {
        for (Node node : connectedNodes) {
            // we are only considering those nodes that are directly connected
            if (node.isNearby()) {
                results.add(node.getId());
            }
        }
    }
}

}

更多详情请查看Android Dev

【讨论】:

  • 我尝试过这样做,但有一些我不明白的地方:当我调用 getCapability() 方法时,我总是有结果,即使我更改了功能的名称。如果名称错误,我不应该什么都检测不到吗?
  • 如果您的手机只有一个连接(比如说手表),则功能正常工作,但如果它有两个以上连接(手表 + 健康手环 + 信标),则系统检查合适的名称,您将得到那个节点。请查看developer.android.com/training/wearables/data-layer/…
  • 这应该被标记为正确答案,因为这实际上会检查连接的节点是否磨损或玻璃或信标。
【解决方案4】:

我正在使用一种更简单的方法,适合我的用例,检查是否安装了 android wear 应用程序:

    try {
        getPackageManager().getPackageInfo("com.google.android.wearable.app", PackageManager.GET_META_DATA);
    } catch (PackageManager.NameNotFoundException e) {
        //android wear app is not installed
    }

【讨论】:

  • 这实际上比使用蓝牙管理器更有帮助,并且它为您节省了蓝牙权限。
  • 仅仅检查是否安装了另一个应用程序并不意味着它们与可穿戴设备配对。检查连接的节点(在上面的示例中)并检查配对的蓝牙设备是唯一确定的方法
  • @Nlinscott - 如前所述,我的方法更简单,适用于特定用例。添加的新答案包括我的解决方案,并在发表此评论时被投票了 6 次,这进一步证明了这一点。
  • 它也没有回答 OP 的问题。我确信它在某些情况下有效,但对寻找解决方案的其他人没有帮助
【解决方案5】:

检查配对设备

您可以检查用户的手表是否已与他的设备配对,而当时无需连接。这样更好,因为这样在检测时不必连接手表。

BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();

Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
    for (BluetoothDevice device : pairedDevices) {
        if(device.getDeviceClass()==BluetoothClass.Device.WEARABLE_WRIST_WATCH){
            Log.d("Found", "Paired wearable: "+ device.getName() + ", with address: " + device.getAddress());
        {
    {
} else {
    Toast.makeText(this, "No paired wearables found", Toast.LENGTH_SHORT).show();
}

请注意,此代码需要清单中的蓝牙权限。

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

【讨论】:

    【解决方案6】:

    我项目中的 Kotlin 代码:

    private val clientDataModel by lazy { ClientDataModel.getClientModelObject(this) }
    
    private fun checkWearableStatus() {
        lifecycleScope.launch {
            try {
    
                val nodes: List<Node> = nodeClient.connectedNodes.await()
                if (nodes.count() <= 0) {
                    // No watch is connected
                    Log.d(TAG, "no wear devices was found )-: ")
                }
                else if(nodes.filter{ it.isNearby }.count() == 0)
                {
                    Log.d(TAG, "there are paired devices but they are not near by or not connected...")
                }
                else {
                    // Display connected devices
                    for (n in nodes) {
                        Log.d(TAG, "Wear devices: " + n.displayName)
                    }
                }
            } catch (ex: Exception) {
                Log.d(TAG, "Error detecting wearable devices: ${ex.message.toString()}")
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多