Android Things 全解析
Android Things 正式接替 Brillo 亮相,名稱的改變帶來了什么新的內容,廣大 Android 開發者如何進入這一新的領域,通過本文,你不僅會了解 Android Things 的來龍去脈,也會直接通過代碼來體驗開發帶給你的魅力。
Android Everywhere
一張 Google I/O 2015上的舊圖,清晰的展示了 Android 的歷史和未來。
Android
處于中心的 Android Mobile,已經占據了全球手機市場絕大多數份額,幾十億部 Andriod 手機,構成了 Android 生態系統最堅實的基礎。
Android TV
隨著著電視大屏發展的腳步,Android TV 也成了所有電視盒子和智能電視的不二之選,主要歸功于 Android 硬件系統的開放、龐大的開發者群體、完整的工具鏈。如果說手機端還有 iOS 將近 20% 的份額,在 TV 端,目測 tvOS 不到 2%,Android TV 也就代表了整個智能電視,國內更是 100% 的 Android TV,Apple TV 沒有國行版本。
Android Wear
讓你的應用跑在手表上,同樣使用熟悉的開發工具,主要是面向海外的應用,由于國內 Android Mobile 嚴重分裂,而 Android Wear 需要依賴手機的支持。
Android Auto
針對汽車的使用場景進行優化,有了 Android Auto 就不用上車后就是找電源線,然后開導航,再把手機放到各種架子上,而是直接把 Android Mobile 放到原生底座上,直接使用語音和易操作的中控大屏。
Android Chromebook
從 Chrome 操作系統版本 M53 開始,可以直接使用 Chromebook 中的 Google Play Store 下載和使用 Android 應用,現在使用的 Gogole Chrome 版本是55,那么絕大多數已有 Chromebook 都已經支持 Android 應用,新的 Chromebook 自然都會支持。
Android 和 Chrome 兩大系統的合并,除了帶來了 Android 豐富的應用以外,對于用戶最大的好處就是自動更新了,Chrome 自動下載更新,下次重新打開/啟動時自動應用更新,從 Android Nougat 開始,Android 系統也將使用這種更新機制。
根據 IDC 報告,Chromebook 在 2016 年第一季度的出貨量已經在美國市場超越了Mac,特別是由于教育市場的大量需求。
這里,還要注意,Chromebook 使用的 Chrome OS 和 Google Chrome 高度共享代碼,既然 Android 應用可以在 Chromebook 上運行,當未來在 Mac/Windows/Linux 上可以時,你也不要感到驚訝。
Android Things
終于到了今天的主角登場,Android Things!先看外表:
再看內部核心硬件:
它的愿景就是將無數的的設備連接起來,Android Things 作為物聯網的大腦,使用公開協議 Weave 與廣大的傳感器/外部設備進行對話。
不像 Android 其它系統,Android Things 大多數情況下只在后臺以服務方式運行,沒有顯示屏,默默的與打印機、門鎖、烤箱、燈泡、插座這些設備一起提供服務。
Android Things 全解析
Android Things 架構
先看 Brillo 和 Android Things 的架構圖進行對比:
這是 Brillo:
這是 Android Things:
可以很清楚的看出來:
-
Brillo 使用 C/C++ 基于 NDK 進行開發,Android Things 通過 Java API 面向廣大的 Android 和 Java 開發者,就算是新手,Android 的也是極易上手的。各位苦于嵌入式開發各種工具坑的福音到了,對于性能和底層要求高的部分仍然可以用 NDK 編寫,在 Android Studio 里調試 NDK 代碼也和 Java 代碼一樣的簡單。
-
Android Studio,Android SDK,Play service 和 Firebase,這些工具和 Service 形成了完整易用的工具鏈。
-
Android Things 出生最晚,更新條件也是最好的,直接使用 Android Nougat 的自動后臺更新機制,最大限度的提高系統的安全性。
廣泛的硬件平臺支持
現在支持以下3款硬件:
1)Intel Edison
2)NXP Pico
3)Raspberry Pi 3
Hello Android Things
買到的開發版都是沒有裝操作系統系統的,第一步先把 Android Things 刷到板子里。
Flash image (刷機):
以Intel Edison為例:
0.Android SDK Platform Tools 25.0.3以上,fastboot 工具添加到 PATH 環境變量中,以便從任意目錄運行。
1. 下載后打Intel Flash Tool,加打開下載好的對應刷機包。
2. 使用 USB 線鏈接 Edison,如果 Edison 沒有顯示,換 USB 口和線試試。
3. Start to Flash(開始刷機)
4. 使用 Fastboot 刷入系統鏡像,此時需要幾十秒,光 System.img 就有 500 多M。
5. 刷入 Google Service 鏡像。
6. 刷入 OEM 鏡像。
7. 重啟
8. 驗證系統狀態。
如果出現以下 Error,把 Intel Flash Tool 關掉,重新連接下 USB。
Connecting WIFI (聯網)
依然是熟悉的 adb 命令和服務啟動參數
用 logcat 查看網絡狀態
Ping 檢測
Hello Android Things 項目
1. Android Studio 中新建項目。
2.在 build.gralde 中添加依賴 com.google.android.things:androidthings
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' }
此處依賴方式是 provided,讓 Android Things 使用系統中的庫。
添加 activity
添加一個主 activity 并配置 AndroidManifest.xml
在 Activity 中輸入 Hello World
運行輸出
直接 Command+R,可以在 logcat 窗口中看到結果了。
Peripheral I/O
不滿足于 Hello Android Things ,繼續來使用 Android Things 對外設進行操作。
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; } } }
使用 Button driver 對 LED 燈進行開關操作。
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; } }
運行到如下的 Raspberry Pi 3 中,使用按鈕來控制 LED 燈。
來自:http://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652040619&idx=1&sn=30aa2b9f34a6574f4d22ce30bd15665e&chksm=808d4deeb7fac4f887dce4f4dbb67319c5161705113b43905843fee237154306405e5b425722#rd