この記事では Android Studio 2.1.2 を使用しています。
大学の研究室で開催している勉強会の資料共有とアーカイブのためにQiitaに投稿しています。
AndroidアプリからGoogleのAPIを用いて様々なGoogleのサービスを利用します。
最終的にはセンサーデータをGoogleのSpreadsheetにアップロードします。
APIとは
APIはざっくりと説明すると他の人が用意してくれた便利なライブラリのことです。
プログラミングはすべて自分で作るのには限界があるためAPIを組み合わせてアプリを作っていくことが多いと思われます。
今回はそんなAPIについて学んでいきたいと思います
Google スプレッドシート とは
Excelのような表計算ソフトをWebブラウザでも使えるようにしたものです。
インターネット上で動くためプログラミングで通信し利用することができます。
Excelと同様計算したり表にまとめたりすることが得意なのでセンサーデータを保存したりまとめたりすることを目的に進めていきたいと思います。
APIでできること
Googleのスプレッドシートを作成、閲覧、編集、削除など基本的なことはできます。
今回は作業を簡単にするために予め自分で用意したスプレッドシートに対しひたすら書き込んでいくプログラムを作成していきます。
GoogleのAPIを利用するために
GoogleのAPIを利用するためには開発者としての登録とどの機能を使うか選択する必要があります。
さらに実際に利用する際には認証が必要になるためアプリ開発に用いるにはすこし難しいと感じています。
開発者として登録する
まずはGoogle API Consoleにアクセスしプロジェクトを作成します。
大学や企業のアカウントなどでは以下のように利用できない場合があります。この表示が出た時は通常のGoogleアカウントにします。
プロジェクトを作成する
勉強会で使用するプロジェクトを作成します。
画面右上周辺の「プロジェクトを選択」をクリックし「プロジェクトの作成」をクリックしてください。
プロジェクト名は好きなもので構いません。入力したら「作成」をクリックします。
プロジェクトの作成には1分ほどかかりますので待ちます。
利用するAPIを選択する
今回はSheetsAPIを用いるためGoogle Apps APIの中にあるSheetsAPIを選択します。
「有効にする」をクリックします。
警告が出てきますので「認証情報に進む」をクリックします。
今回はSheetsAPIを選択し、呼び出す場所をAndroidとします。
次にこのような画面になります
ここでAPIを使用するAndroidアプリの「パッケージ名」と「フィンガープリント」が必要になるため調べていきます
パッケージ名を調べる
まずは空のAndroidアプリを作成します
EmptyActivityを選択しアプリを作成しました
はじめに生成されたbuild.gradle(Module: app)を開きます。
apply plugin: 'com.android.application'
android {
...
defaultConfig {
applicationId "パッケージ名"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
...
}
...
android -> defaultConfig -> applicationId がパッケージ名になります
フィンガープリントを調べる
これが少し面倒です
まずはJavaのインストールされたフォルダのbinフォルダを開きます
大抵の場合C:\Program Files\Java\jre7\bin
となっていると思われますが適宜調べてください
そしてコマンドプロンプトを開きます(Shift+右クリックで簡単に開けます)
次にAndroidStudioが使用するkeystoreファイルを探します
こちらは基本的にC:\Users\ユーザー名\.android
となります
このフォルダの中にdebug.keystoreというファイルがあるはずです
先ほど開いたコマンドプロンプトに
keytool -list -v -keystore
と入力しdebug.keystoreファイルをコマンドプロンプトにドラッグします
するとコマンドプロンプト上には
C:\Program Files\Java\jre7\bin>keytool -list -v -keystore C:\Users\ユーザ名\.android\debug.keystore
のように表示されますのでEnterキーを押して実行します
パスワードの入力を求められるのでandroid
と入力します
この時に入力しても何も表示されませんがそのままEnterキーを押します
すると様々な情報が表示されますがフィンガープリントはSHA1の部分になります
※一部隠してあります
パッケージ名とフィンガープリントを登録する
再びGoogleの登録画面にもどり2つを登録します
入力したら「APIキーを生成する」をクリックし「完了」をクリックします
このような画面になります
ここまででAPIを利用する準備は整いました
アプリ側の準備をする
APIを使用するために必要なライブラリを読み込みます
まずは(Module: app)と表記されているbuild.gradleを編集します
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "パッケージ名"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
// ここから下を追加
compile 'com.google.android.gms:play-services-auth:9.0.2'
compile 'pub.devrel:easypermissions:0.1.5'
compile('com.google.api-client:google-api-client-android:1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
compile('com.google.apis:google-api-services-sheets:v4-rev10-1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
}
基本的には生成されたままですがdependenciesに幾つか追記しています
次にAndroidManifest.xmlを編集します
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="daiki.example.com.androidsheetapi">
<!--ネットワーク接続の許可を追加-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--meta情報を追加-->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
</manifest>
2か所追加しました
編集するためのスプレッドシートを用意する
Google スプレッドシートにアクセスして右下の+ボタンを押して新しくスプレッドシートを作成します
新しく作成されると自動的にそのスプレッドシートが開かれます
アクセスがうまくできているかを確認するために4つだけ追加します
サンプルコードをコピーする
公式のサンプルコードをそのまま一度写します
1行目はそれぞれ異なるはずので1行目以外をすべてコピペします
サンプルコードを自分用にアレンジする
さきほど作成したスプレッドシートにアクセスするようにプログラムを変更していきます
package パッケージ名;
import ...;
public class MainActivity extends Activity
...
/**
* An asynchronous task that handles the Google Sheets API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
...
/**
* Fetch a list of names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
* @return List of names and majors
* @throws IOException
*/
private List<String> getDataFromApi() throws IOException {
String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
String range = "Class Data!A2:E";
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(spreadsheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
results.add("Name, Major");
for (List row : values) {
results.add(row.get(0) + ", " + row.get(4));
}
}
return results;
}
...
}
}
このgetDataFromApiという関数を変更します
まずspreadsheetIdを先ほど作成したスプレッドシートのIDにします
IDはURLの以下の部分です
次にrangeを先ほど追加したデータの範囲にしたいのでシート1!A1:D1
にします
そしてデータをresultに追加していく部分も変更します
for (List row : values) {
results.add(
row.get(0) + ", " +
row.get(1) + ", " +
row.get(2) + ", " +
row.get(3)
);
}
それでは実行してみます
アプリが起動したらCAlL GOOGLE SHEETS APIを押します
先ほど入力したデータがとれました
書き込みをしてみる
次にデータを書き込むようなコードを追記します
package sheetsquickstart.example.com.sheetsquickstart;
import ...;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
...
/**
* An asynchronous task that handles the Google Sheets API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
...
/**
* Background task to call Google Sheets API.
*
* @param params no parameters needed for this task.
*/
@Override
protected List<String> doInBackground(Void... params) {
try {
putDataFromApi(); //ボタンを押した時に反応させるために追記
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* データを書き込むメソッド
* @throws IOException
*/
private void putDataFromApi() throws IOException {
String spreadsheetId = "スプレッドシートのID";
String range = "シート1!A2:D2";
ValueRange valueRange = new ValueRange();
List row = new ArrayList<>();
List col = Arrays.asList("This", "is", "test", "test");
row.add(col);
valueRange.setValues(row);
valueRange.setRange(range);
this.mService.spreadsheets().values()
.update(spreadsheetId, range, valueRange)
.setValueInputOption("USER_ENTERED")
.execute();
}
...
}
}
これでアプリのボタンを押すとスプレッドシートが以下のように更新されます
センサーデータをアップする
センサーデータを取得する
まずはSensorEventListenerを実装しSensorManagerなどの初期化を行います
package sheetsquickstart.example.com.sheetsquickstart;
import ...;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks, SensorEventListener {
SensorManager manager;
Sensor sensor;
private List data = new ArrayList<>(); // 加速度センサーのデータを保持するための変数
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
manager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 今回は加速度を使用します
}
@Override
public void onSensorChanged(SensorEvent event) {
data.add(Arrays.asList(
event.timestamp,
event.values[0],
event.values[1],
event.values[2]
));
while (data.size() > 50) {
data.remove(data.size() - 1); // 送信するデータ数を50個に制限しています
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 使用しません
}
@Override
protected void onResume() {
super.onResume();
manager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
}
@Override
protected void onPause() {
super.onPause();
manager.unregisterListener(this);
}
センサーデータを送信する
送信する部分のプログラムを変更しセンサーデータを送信します
package sheetsquickstart.example.com.sheetsquickstart;
import ...;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
...
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
...
/**
* データを書き込むメソッド
*
* @throws IOException
*/
private void putDataFromApi() throws IOException {
List values = data;
String spreadsheetId = "スプレッドシートのID";
String range = "シート1!A2:D" + (values.size() + 1);
ValueRange valueRange = new ValueRange();
valueRange.setValues(values);
valueRange.setRange(range);
this.mService.spreadsheets().values()
.update(spreadsheetId, range, valueRange)
.setValueInputOption("USER_ENTERED")
.execute();
}
...
}
}
これでボタンを押した時に直近50個のセンサーデータが送信されます
せめて操作だけでもしてみる!
サンプルコードを取る
git clone https://github.com/googlecodelabs/sheets-api.git
Gitコマンドでサンプルプログラムを取得します
cloneされたフォルダ内のstep10が完成なのでそちらのフォルダをコマンドプロンプトで開きます
npm install
を実行してライブラリを取得します
APIキーを追加する
現在Android用の認証情報だけなのでテスト用にWeb用のものも作成します
Google API Consoleにアクセスし
先ほど作成したプロジェクトを選択し「認証情報」をクリック
認証情報の作成からOAuthクライアントIDを選択します
ウェブアプリケーションを選択し生成元にはhttp://localhost:3000
と指定します
作成を行うと client IDが出てきます
Client IDをコピーし
step10/views/layout.handlebarsの43行目の{YOUR CLIENT ID}を先ほどの client IDにします
実行してみる
step10のフォルダを開いているコマンドプロンプトでnpm start
を実行しhttp://localhost:3000にアクセスしてみます
右のCreateボタンによりスプレッドシートがGoogle Driveに追加されデータも編集できることが確認できると思います
今回の勉強会はここまでしかできていません
いそいで続きつくります…