Android Things 全解析
yvgodargj
8年前
<p>Android Things 正式接替 Brillo 亮相,名称的改变带来了什么新的内容,广大 Android 开发者如何进入这一新的领域,通过本文,你不仅会了解 Android Things 的来龙去脉,也会直接通过代码来体验开发带给你的魅力。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/b3c322c68a8013f7dc04a3f1984ffab8.png"></p> <p><strong>Android Everywhere</strong></p> <p>一张 Google I/O 2015上的旧图,清晰的展示了 Android 的历史和未来。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/223661e40b85332864478735fde88022.jpg"></p> <p><strong>Android</strong></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/67c13d8e71a507646f98bd7e2d14eec3.jpg"></p> <p>处于中心的 Android Mobile,已经占据了全球手机市场绝大多数份额,几十亿部 Andriod 手机,构成了 Android 生态系统最坚实的基础。</p> <p><strong>Android TV</strong></p> <p><img src="https://simg.open-open.com/show/c29a711f898e53a2a89b6df54da93e6f.jpg"></p> <p>随着着电视大屏发展的脚步,Android TV 也成了所有电视盒子和智能电视的不二之选,主要归功于 Android 硬件系统的开放、庞大的开发者群体、完整的工具链。如果说手机端还有 iOS 将近 20% 的份额,在 TV 端,目测 tvOS 不到 2%,Android TV 也就代表了整个智能电视,国内更是 100% 的 Android TV,Apple TV 没有国行版本。</p> <p><strong>Android Wear</strong></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/82b0c04f1be7bbdb6d3feed2dab54851.jpg"></p> <p>让你的应用跑在手表上,同样使用熟悉的开发工具,主要是面向海外的应用,由于国内 Android Mobile 严重分裂,而 Android Wear 需要依赖手机的支持。</p> <p><strong>Android Auto</strong></p> <p><img src="https://simg.open-open.com/show/c298b226ed76253747a0276ec32b1f79.jpg"></p> <p>针对汽车的使用场景进行优化,有了 Android Auto 就不用上车后就是找电源线,然后开导航,再把手机放到各种架子上,而是直接把 Android Mobile 放到原生底座上,直接使用语音和易操作的中控大屏。</p> <p><strong>Android Chromebook</strong></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/e95cb65e65aeb7bd47be8a9d868b8caa.jpg"></p> <p>从 Chrome 操作系统版本 M53 开始,可以直接使用 Chromebook 中的 Google Play Store 下载和使用 Android 应用,现在使用的 Gogole Chrome 版本是55,那么绝大多数已有 Chromebook 都已经支持 Android 应用,新的 Chromebook 自然都会支持。</p> <p>Android 和 Chrome 两大系统的合并,除了带来了 Android 丰富的应用以外,对于用户最大的好处就是自动更新了,Chrome 自动下载更新,下次重新打开/启动时自动应用更新,从 Android Nougat 开始,Android 系统也将使用这种更新机制。</p> <p>根据 IDC 报告,Chromebook 在 2016 年第一季度的出货量已经在美国市场超越了Mac,特别是由于教育市场的大量需求。</p> <p>这里,还要注意,Chromebook 使用的 Chrome OS 和 Google Chrome 高度共享代码,既然 Android 应用可以在 Chromebook 上运行,当未来在 Mac/Windows/Linux 上可以时,你也不要感到惊讶。</p> <p><strong>Android Things</strong></p> <p>终于到了今天的主角登场,Android Things!先看外表:</p> <p>再看内部核心硬件:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/c3e65d2cf4880bced8423b224cab17be.jpg"></p> <p>它的愿景就是将无数的的设备连接起来,Android Things 作为物联网的大脑,使用公开协议 Weave 与广大的传感器/外部设备进行对话。</p> <p>不像 Android 其它系统,Android Things 大多数情况下只在后台以服务方式运行,没有显示屏,默默的与打印机、门锁、烤箱、灯泡、插座这些设备一起提供服务。</p> <p><strong>Android Things 全解析</strong></p> <p><strong>Android Things 架构</strong></p> <p>先看 Brillo 和 Android Things 的架构图进行对比:</p> <p>这是 Brillo: </p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/94b7bb0bcf82c263dbf1a25f6bc6f40b.jpg"></p> <p>这是 Android Things:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/6ca06586e99d2a266f4037bb7d3a0e43.jpg"></p> <p>可以很清楚的看出来:</p> <ul> <li> <p>Brillo 使用 C/C++ 基于 NDK 进行开发,Android Things 通过 Java API 面向广大的 Android 和 Java 开发者,就算是新手,Android 的也是极易上手的。各位苦于嵌入式开发各种工具坑的福音到了,对于性能和底层要求高的部分仍然可以用 NDK 编写,在 Android Studio 里调试 NDK 代码也和 Java 代码一样的简单。</p> </li> <li> <p>Android Studio,Android SDK,Play service 和 Firebase,这些工具和 Service 形成了完整易用的工具链。</p> </li> <li> <p>Android Things 出生最晚,更新条件也是最好的,直接使用 Android Nougat 的自动后台更新机制,最大限度的提高系统的安全性。</p> </li> </ul> <p>广泛的硬件平台支持</p> <p>现在支持以下3款硬件:</p> <p>1)Intel Edison</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/d23aaf5acae3c3234ec2c4ca367a3aee.jpg"></p> <p>2)NXP Pico</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/7dd2cd0c30a869bbb82c967a3adcb1d7.jpg"></p> <p>3)Raspberry Pi 3</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/265b5aa1034459ccf025e4a46b8d5249.jpg"></p> <p><strong>Hello Android Things</strong></p> <p>买到的开发版都是没有装操作系统系统的,第一步先把 Android Things 刷到板子里。</p> <p>Flash image (刷机):</p> <p>以Intel Edison为例:</p> <p>0.Android SDK Platform Tools 25.0.3以上,fastboot 工具添加到 PATH 环境变量中,以便从任意目录运行。</p> <p>1. 下载后打Intel Flash Tool,加打开下载好的对应刷机包。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/88b7c574839b8a0fcb1ad9524127c6a3.jpg"></p> <p>2. 使用 USB 线链接 Edison,如果 Edison 没有显示,换 USB 口和线试试。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/1d97929ff9eb82342d8f6cba3dc39306.jpg"></p> <p>3. Start to Flash(开始刷机)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/7378cd0501b06698b522b67fab6f1a6b.jpg"></p> <p>4. 使用 Fastboot 刷入系统镜像,此时需要几十秒,光 System.img 就有 500 多M。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/808b2623642a00f27aa972152e9929e8.jpg"></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/834f26431aaca112c4c0afaac504da2f.jpg"></p> <p>5. 刷入 Google Service 镜像。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/898d8b7d882b5ad00d13b5c4e4c804ea.jpg"></p> <p>6. 刷入 OEM 镜像。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/a76d51a6074d961b999b0190cbcdbcd6.jpg"></p> <p>7. 重启</p> <p>8. 验证系统状态。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/7d0aaafed8237deb868a7a013b748720.jpg"></p> <p>如果出现以下 Error,把 Intel Flash Tool 关掉,重新连接下 USB。</p> <p><img src="https://simg.open-open.com/show/54004d9a8cdabf9a0a23bc1ee477de3b.jpg"></p> <p><strong>Connecting WIFI (联网)</strong></p> <p>依然是熟悉的 adb 命令和服务启动参数</p> <p><img src="https://simg.open-open.com/show/14c7a73c759adb5b1dbe02cece608bdc.png"></p> <p>用 logcat 查看网络状态</p> <p><img src="https://simg.open-open.com/show/210c843cb0c23c42f038f081a71ca557.png"></p> <p>Ping 检测</p> <p><img src="https://simg.open-open.com/show/bab7be65f18243776255f60ba9daefb6.png"></p> <p><strong>Hello Android Things 项目</strong></p> <p>1. Android Studio 中新建项目。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/6990efc4596124e9632d0e28abd4f753.jpg"> <img src="https://simg.open-open.com/show/471bda14cdbede4aa8f1b43052914271.jpg"></p> <p>2.在 build.gralde 中添加依赖 com.google.android.things:androidthings</p> <pre> apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.geekdev.alpha.androidthings" minSdkVersion 24 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) provided 'com.google.android.things:androidthings:0.1-devpreview' compile 'com.android.support:appcompat-v7:25.1.0' testCompile 'junit:junit:4.12' }</pre> <p>此处依赖方式是 provided,让 Android Things 使用系统中的库。</p> <p><strong>添加 activity</strong></p> <p>添加一个主 activity 并配置 AndroidManifest.xml</p> <p><img src="https://simg.open-open.com/show/101a7f16be7e6f8b0048cf49909170eb.jpg"></p> <p>在 Activity 中输入 Hello World</p> <p><img src="https://simg.open-open.com/show/c201cc764bbaf904a5c3391a10d3fdf1.png"></p> <p><strong>运行输出</strong></p> <p>直接 Command+R,可以在 logcat 窗口中看到结果了。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/099275c8bab7ae786b4cd0d11af7532a.jpg"></p> <p><strong>Peripheral I/O</strong></p> <p>不满足于 Hello Android Things ,继续来使用 Android Things 对外设进行操作。</p> <pre> package com.geekdev.alpha.androidthings; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.widget.Button; import com.google.android.things.contrib.driver.button.ButtonInputDriver; import com.google.android.things.pio.Gpio; import com.google.android.things.pio.PeripheralManagerService; import java.io.IOException; /** * Created by Alpha. * <p> * Example of using Button driver for toggling a LED. * <p> * This activity initialize an InputDriver to emit key events when the button GPIO pin state change * and flip the state of the LED GPIO pin. * <p> * You need to connect an LED and a push button switch to pins specified in {@link BoardDefaults} * according to the schematic provided above. */ public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); private Gpio mLedGpio; private ButtonInputDriver mButtonInputDriver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "Hello Android Things!"); Log.i(TAG, "Starting ButtonActivity"); PeripheralManagerService pioService = new PeripheralManagerService(); try { Log.i(TAG, "Configuring GPIO pins"); mLedGpio = pioService.openGpio(BoardDefaults.getGPIOForLED()); mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); Log.i(TAG, "Registering button driver"); // Initialize and register the InputDriver that will emit SPACE key events // on GPIO state changes. mButtonInputDriver = new ButtonInputDriver( BoardDefaults.getGPIOForButton(), Button.LogicState.PRESSED_WHEN_LOW, KeyEvent.KEYCODE_SPACE); mButtonInputDriver.register(); } catch (IOException e) { Log.e(TAG, "Error configuring GPIO pins", e); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_SPACE) { // Turn on the LED setLedValue(true); return true; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_SPACE) { // Turn off the LED setLedValue(false); return true; } return super.onKeyUp(keyCode, event); } /** * Update the value of the LED output. */ private void setLedValue(boolean value) { try { mLedGpio.setValue(value); } catch (IOException e) { Log.e(TAG, "Error updating GPIO value", e); } } @Override protected void onDestroy() { super.onDestroy(); if (mButtonInputDriver != null) { mButtonInputDriver.unregister(); try { mButtonInputDriver.close(); } catch (IOException e) { Log.e(TAG, "Error closing Button driver", e); } finally { mButtonInputDriver = null; } } if (mLedGpio != null) { try { mLedGpio.close(); } catch (IOException e) { Log.e(TAG, "Error closing LED GPIO", e); } finally { mLedGpio = null; } mLedGpio = null; } } }</pre> <p>使用 Button driver 对 LED 灯进行开关操作。</p> <pre> package com.geekdev.alpha.androidthings; import android.os.Build; import com.google.android.things.pio.PeripheralManagerService; import java.util.List; /** * Created by Alpha. */ public class BoardDefaults { private static final String DEVICE_EDISON_ARDUINO = "edison_arduino"; private static final String DEVICE_EDISON = "edison"; private static final String DEVICE_RPI3 = "rpi3"; private static final String DEVICE_NXP = "imx6ul"; private static String sBoardVariant = ""; /** * Return the GPIO pin that the LED is connected on. * For example, on Intel Edison Arduino breakout, pin "IO13" is connected to an onboard LED * that turns on when the GPIO pin is HIGH, and off when low. */ public static String getGPIOForLED() { switch (getBoardVariant()) { case DEVICE_EDISON_ARDUINO: return "IO13"; case DEVICE_EDISON: return "GP45"; case DEVICE_RPI3: return "BCM6"; case DEVICE_NXP: return "GPIO4_IO21"; default: throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE); } } /** * Return the GPIO pin that the Button is connected on. */ public static String getGPIOForButton() { switch (getBoardVariant()) { case DEVICE_EDISON_ARDUINO: return "IO12"; case DEVICE_EDISON: return "GP44"; case DEVICE_RPI3: return "BCM21"; case DEVICE_NXP: return "GPIO4_IO20"; default: throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE); } } private static String getBoardVariant() { if (!sBoardVariant.isEmpty()) { return sBoardVariant; } sBoardVariant = Build.DEVICE; // For the edison check the pin prefix // to always return Edison Breakout pin name when applicable. if (sBoardVariant.equals(DEVICE_EDISON)) { PeripheralManagerService pioService = new PeripheralManagerService(); List<String> gpioList = pioService.getGpioList(); if (gpioList.size() != 0) { String pin = gpioList.get(0); if (pin.startsWith("IO")) { sBoardVariant = DEVICE_EDISON_ARDUINO; } } } return sBoardVariant; } }</pre> <p>运行到如下的 Raspberry Pi 3 中,使用按钮来控制 LED 灯。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/4da99db533dcb0ce8c5170861debdea3.jpg"></p> <p> </p> <p> </p> <p>来自:http://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652040619&idx=1&sn=30aa2b9f34a6574f4d22ce30bd15665e&chksm=808d4deeb7fac4f887dce4f4dbb67319c5161705113b43905843fee237154306405e5b425722#rd</p> <p> </p>