Help us understand the problem. What is going on with this article?

Android勉強会 vol.4 GoogleSpreadsheetにセンサーデータをアップロードする

More than 3 years have passed since last update.

この記事では 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アカウントにします。
無題.jpg

プロジェクトを作成する

勉強会で使用するプロジェクトを作成します。
無題.jpg
画面右上周辺の「プロジェクトを選択」をクリックし「プロジェクトの作成」をクリックしてください。
無題.jpg
プロジェクト名は好きなもので構いません。入力したら「作成」をクリックします。
プロジェクトの作成には1分ほどかかりますので待ちます。

利用するAPIを選択する

今回はSheetsAPIを用いるためGoogle Apps APIの中にあるSheetsAPIを選択します。
無題.jpg
「有効にする」をクリックします。
無題.jpg
警告が出てきますので「認証情報に進む」をクリックします。
無題.jpg
今回はSheetsAPIを選択し、呼び出す場所をAndroidとします。
無題.jpg
次にこのような画面になります
無題.jpg
ここでAPIを使用するAndroidアプリの「パッケージ名」と「フィンガープリント」が必要になるため調べていきます

パッケージ名を調べる

まずは空のAndroidアプリを作成します
EmptyActivityを選択しアプリを作成しました
はじめに生成されたbuild.gradle(Module: app)を開きます。

build.gradle
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の部分になります
無題.jpg
※一部隠してあります

パッケージ名とフィンガープリントを登録する

再びGoogleの登録画面にもどり2つを登録します
無題.jpg
入力したら「APIキーを生成する」をクリックし「完了」をクリックします
無題.jpg
このような画面になります

ここまででAPIを利用する準備は整いました

アプリ側の準備をする

APIを使用するために必要なライブラリを読み込みます
まずは(Module: app)と表記されているbuild.gradleを編集します

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を編集します

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 スプレッドシートにアクセスして右下の+ボタンを押して新しくスプレッドシートを作成します
無題.jpg
新しく作成されると自動的にそのスプレッドシートが開かれます
アクセスがうまくできているかを確認するために4つだけ追加します
無題.jpg

サンプルコードをコピーする

公式のサンプルコードをそのまま一度写します
1行目はそれぞれ異なるはずので1行目以外をすべてコピペします

サンプルコードを自分用にアレンジする

さきほど作成したスプレッドシートにアクセスするようにプログラムを変更していきます

MainActivity.java
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の以下の部分です
無題.jpg
次に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を押します

device-2016-07-20-105720.jpg

先ほど入力したデータがとれました

書き込みをしてみる

次にデータを書き込むようなコードを追記します

MainAcitivty.java
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();
        }

        ...
    }
}

これでアプリのボタンを押すとスプレッドシートが以下のように更新されます
無題.jpg

センサーデータをアップする

センサーデータを取得する

まずはSensorEventListenerを実装しSensorManagerなどの初期化を行います

MainActivity.java
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);
    }

センサーデータを送信する

送信する部分のプログラムを変更しセンサーデータを送信します

MainActivity.java
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個のセンサーデータが送信されます

無題.jpg

せめて操作だけでもしてみる!

サンプルコードを取る

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に追加されデータも編集できることが確認できると思います

今回の勉強会はここまでしかできていません
いそいで続きつくります…

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした