如何创建一个Android Wear OS应用程序

1,064 阅读6分钟

如何创建一个Android Wear OS应用程序

在开发移动应用程序时,我们通常只关注两种类型的设备:平板电脑和智能手机。每当我们开始一个新的Android Studio项目时,我们一般都会遇到其他类型设备的建议模板。

你有没有考虑过如何为可穿戴设备构建应用程序?

由于独特的使用环境和较小的屏幕,智能手表在设计和互动性方面与智能手机不同。布局更简单,更依赖滑动动作来操作。

在这篇文章中,我们将学习如何为Wear OS可穿戴设备创建一个应用程序。

前提条件

要完成这个教程,你应该有。

  • 在你的机器上安装了[Android Studio]。
  • 具有kotlin编程语言的基本知识。

Wear OS与Android相比有何不同?

Wear OS是一个专门为可穿戴设备设计的新平台。虽然它以安卓为中心,但它提供了一个独特的外观和一套独特的功能。

如果你已经熟悉了Android移动应用开发,Wear OS不应该是一个挑战。

专为Wear OS设计的软件包

  • android.webkit- 是一个开源的网页渲染引擎,已经成为移动浏览器的主流。它是使用KDE桌面环境的KHTMLKJS模块的代码创建的。
  • android.print- 包括用于在Android应用程序中实现打印功能的类。其他与打印相关的更专业的包也使用了这些基本类。
  • android.app.backup- 包括备份和恢复功能。因此,当启用了备份复制的应用程序被重新安装时,旧的用户数据可以被恢复。
  • android.appwidget- 包含开发应用程序部件所需的工具,允许用户访问应用程序的数据和服务,而不必自己创建解决方案。
  • android.hardware.usb- 允许基于Android的设备与USB外围设施进行通信。

在Android Studio上创建一个Wear OS项目

当为智能手表建立一个Android Wear应用程序时,根据项目要求或你的口味,选择Wear OS标签、一个空的Activity或任何其他可用的选项。

在你的应用程序的包里,会马上出现两个模块:一个是智能手表的穿戴模块,一个是平板电脑和手机的应用模块。

如果你希望将智能手表功能添加到现有的应用程序中,请打开它,从File -> New -> New Module 菜单中挑选Wear OS模块,并进行设置。之后,会出现一个文件夹,上面有所需模块的文件名。

两个不同的.apk.aab 文件将由两个模块创建。然而,它们必须有相同的包名,并且在发布时要经过相同的认证验证。

这一点很重要,因为谷歌服务允许应用程序之间相互通信。你仍然可以在不使用智能手机平台的情况下制作一个Wear OS应用程序。

创建用户界面布局

第一步是为你的应用程序设计一个布局。

布局是对你的应用程序的用户界面的视觉描述。它是显示给用户的应用程序的图形说明。

安卓应用开发的主要关注点之一是巨大的设备范围;各种尺寸、形状和配置。即使涉及到Wear OS,也有各种屏幕风格需要考虑,包括圆形、方形和带有切边的圆形。

Wear OS和Android OS有类似的UI模式。你也可以使用谷歌的Wear UI工具包,该工具包有一套全面的功能要求,以配合智能手表的风格要求。

因此,实施过程得以简化,开发资源得以减少。

要做到这一点,你应该在应用级build.gradle 文件中包括以下依赖性。

dependencies {
    // For the Wear UI Toolkit
    implementation 'com.google.android.support:wearable:2.5.0'
    implementation 'com.android.support:percent:28.0.0'
    implementation 'com.android.support:wear:28.0.0'
    implementation 'androidx.wear:wear:1.0.0'
    compileOnly 'com.google.android.wearable:wearable:2.7.0'

    // For Google services
    implementation 'com.google.android.gms:play-services-wearable:16.0.1'
    implementation 'com.android.support:support-v4:28.0.0'
}

设置清单

Wear OS应用程序的清单与Android智能手机的清单略有不同。

我们必须定义功能和Wear OS库,以及其他元数据。

<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.demo.wear">

    <uses-feature android:name="android.hardware.type.watch" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.DeviceDefault">

        <uses-library
            android:name="com.google.android.wearable"
            android:required="true" />

        <!-- If your software is Standalone, it means it doesn't need to be run on a mobile device. -->

        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

最常见的Wear OS UI组件

工具包中有四个主要的UI元素,值得特别注意,因为它们在Wear OS开发中很有用。

  • WearableLinearLayoutManager- 允许你使用手表的机械轮滚动浏览列表。此外,它还可以将沿屏幕边框定位的对象移到中心,这在采用圆形界面时非常有用。
  • BoxInsetLayout- 是一个安卓的FrameLayout,能够使子项目适应圆形显示。它将它们定位在由屏幕圆形定义的矩形区域内。

对于方形显示,这种转换在系统层面上被忽略。因此,在所有的手表界面中,布局将是类似的。

  • WearableRecyclerView- RecyclerView是一个广泛用于移动应用程序的有用工具,但在这种情况下,它是为手表定制的。由于显示器的弯曲边缘,顶部和底部的视图可能会沿着边缘被截断。因此,这个模式被用来解决这个问题。
  • EdgeItemsCenteringEnabled- 是一个设置,允许你为滚动的项目创建一个弯曲的布局,并改进核心元素,使其在相对较小的屏幕上更容易查看。
  • SwipeDismissFrameLayout是另一个流行的布局,使其可以从左到右滑动。

使用BoxInsetLayout元素的代码示例

<androidx.wear.widget.BoxInsetLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:padding="8dp"
    tools:deviceIds="wear"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="4dp"
        app:layout_boxedEdges="all">

        <ImageButton
            android:background="@android:color/transparent"
            android:layout_height="60dp"
            android:layout_width="60dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:src="@drawable/ic_ok" />

        <TextView
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:text="some text"
            android:textAlignment="center"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <!--In this example, this ImageButton requires an icon named ic_cancel-->
        <ImageButton
            android:background="@android:color/transparent"
            android:layout_height="60dp"
            android:layout_width="60dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:src="@drawable/ic_cancel" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.wear.widget.BoxInsetLayout>

结果。

BoxInsetLayout

使用SwipeDismissFrameLayout元素的代码示例

<?xml version="1.0" encoding="utf-8"?>
<android.support.wear.widget.BoxInsetLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    tools:context=".MainActivity"
    tools:deviceIds="wear">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        app:boxedEdges="none">

        <android.support.wear.widget.SwipeDismissFrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/swipe_dismiss_root" >

            <TextView
                android:id="@+id/test_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="bottom"
                android:text="Swipe to dismiss"/>
        </android.support.wear.widget.SwipeDismissFrameLayout>

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Hello world" />

    </FrameLayout>
</android.support.wear.widget.BoxInsetLayout>

结果。

SwipeDismissFrameLayout

导航

导航指的是允许用户在应用程序中的不同屏幕或目的地之间进行导航、进入和返回的交互。

使用NavigationDrawer

手表应用程序通常没有标题栏,以节省大量的显示空间。当使用ViewPager时,不显示TabLayout,但我们不能确定我们在哪个页面上。

让我们来看看导航栏的效果WearableNavigationDrawerView ,利用它来解决这个问题。

当你从屏幕顶部向下滑动时,会显示一个导航条,显示出当前页面的图标和标题。如果有众多的页面,可以一边滑动页面,一边改变它。

让我们来看看它是如何使用的。我们改变布局文件并使WearableDrawerLayout 根布局,以及添加一个导航栏控件。

<android.support.wear.widget.drawer.WearableNavigationDrawerView
        android:id="@+id/navigation_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navigationStyle="multiPage"/>

为NavigationDrawer设置一个适配器,以及为每个页面设置图标和标题,如下图所示。

class DrawerAdapter(context: Context) : WearableNavigationDrawerView.WearableNavigationDrawerAdapter() {

    private val context = context

    override fun getItemText(pos: Int): CharSequence {
        return when (pos) {
            0 -> "First page"
            else -> "The second page"
        }
    }

    override fun getItemDrawable(pos: Int): Drawable {
        // create two icons and name them as shown below
        return when (pos) {
            0 -> ContextCompat.getDrawable(context, R.drawable.icon_one)!!
            else -> ContextCompat.getDrawable(context, R.drawable.icon_two)!!
        }
    }

    override fun getCount(): Int {
        return 2
    }

}

MainActivity 中设置抽屉。

navigation_drawer.apply{
    setAdapter(DrawerAdapter(this))
    controller.peekDrawer()
    addOnItemSelectedListener { pos ->
    // switch the page
    }
}

结果。

Drawer

远程Intent

这允许你在另一个设备上启动一个活动。这个API目前支持共享意图,动作设置为ACTION_VIEW ,数据URI由setData(Uri)提供,并且有CATEGORY_BROWSABLE 类别存在。

 RemoteIntent.startRemoteActivity(context, nodeId, Intent(Intent.ACTION_VIEW)
     .setData(Uri.parse("http://play.google.com/store/apps/details?id=com.example.myapp")),
     null)

总结

在本教程中,我们已经学会了如何使用ConstraintLayout、SwipeDismissFrameLayout和WearableNavigationDrawerView创建一个基于Android的Wear OS应用。

本教程提供了基本的知识,你可以根据自己的想象力来创建一个穿戴式操作系统应用程序。