GoogleAppsSriptAPI+Android/NFCで出席をとる


今更感はありますが、AppsScriptAPIとNFC搭載のAndroidを使って、出席確認?アプリ的な物を作ってみたいと思います。
ちなみにですが、AppsScriptもAndroidもNFCも少しかじった程度の知識しかございません!
行きます。

GASでAPIを作る

まずはGASで関数を書きます。
とりあえず、ただの文字列をreturnするだけの関数です。

function getIcCardData() {
  var message = 'おつかれさまです';
  return message;
}

作った関数をAPIにし、外部から叩けるようにせねばならない。
以下を参考にさせていただきました。

認証情報の作成についてですが、
今回の呼び出し元はAndroidなので、クライアントIDの作成時に、アプリケーションの種類でAndroidを選びます。
OAuthクライアントIDで。

パッケージ名とSHA-1 署名証明書のフィンガープリントを登録する必要があります。
先に、Androidプロジェクトを作成してしまったほうが良さそうです。

AndroidStudioで、新規Androidプロジェクトを作成します。
上記画像に記載されている通り、作成後のAndroidManifest.xml内のpackage名をコピー、認証情報に貼り付けます。

SHA-1 署名証明書のフィンガープリントですが、こちらも同様に上記の画像の、
コマンドを実行することで、取得可能です。

keytool -exportcert -keystore path-to-debug-or-production-keystore -list -v

太字の部分でkeystoreファイルの場所を指定します。
今回はデバッグ用のkeystoreを使用します。
私の場合(Windows環境)、c:\Users\ユーザー名\.android\debug.keystore でした。
正しくコマンドを入力すると、パスワードを求められます。
debug.keystoreのパスワードはデフォルトだと"Android"となっています。表示されたフィンガープリントのSHA1をコピーし、認証情報に貼り付けて、保存します。

ここまでで、Android QuickstartのSTEP3までが完了しています。

Androidからアクセスしてみる

Android QuickstartのSTEP4~STEP6の対象ファイルを書き換えます。

build.gradleファイルですが、
gradleのバージョンが3.0であったため、以下のように変更しています。
dependencies部分のみの変更で大丈夫そうです。

dependencies {
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
    }
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:design:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    implementation 'com.google.android.gms:play-services-auth:11.8.0'
    implementation 'pub.devrel:easypermissions:0.3.0'
    implementation('com.google.api-client:google-api-client-android:1.23.0') {
        exclude group: 'org.apache.httpcomponents'
    }
    implementation('com.google.apis:google-api-services-script:v1-rev166-1.23.0') {
        exclude group: 'org.apache.httpcomponents'
    }
}

configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
}
と後ろ4つのimplementationを追加しました。

AndroidManifest.xmlですが、
以下の追加のみでokです。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

MainActivity.javaに関してはAndroidQuickStartのコードを全コピーでいけます。
嘘を付きました。
getDataFromApiを少し変更します。

 private List<String> getDataFromApi()
                throws IOException, GoogleAuthException {
            // ID of the script to call. Acquire this from the Apps Script editor,
            // under Publish > Deploy as API executable.
            String scriptId = "APIIDを入力!";

            List<String> folderList = new ArrayList<String>();

            // Create an execution request object.
            ExecutionRequest request = new ExecutionRequest()
                    .setFunction("API関数名を入力!");

            // Make the request.
            Operation op =
                    mService.scripts().run(scriptId, request).execute();

            // Print results of request.
            if (op.getError() != null) {
                throw new IOException(getScriptError(op));
            }
            if (op.getResponse() != null &&
                    op.getResponse().get("result") != null) {
                //文字列を返すのでStringへキャストする
                 String data = (String)(op.getResponse().get("result"));
                 folderList.add(data);
            }

            return folderList;
        }

APIID、呼び出す関数の指定、加えて今回は文字列を受け取るので、戻り値をStringへキャストしています。

以上で準備完了です。
まだでした。今回のスクリプトはspreadsheetにアクセスして操作しようと思っているので、
spreadsheetに紐づくAppsScriptプロジェクトになっています。
スコープの設定が必要です。
クラス変数のSCOPESを以下に書き換えます。
"https://www.googleapis.com/auth/spreadsheets"

追加が必要なスコープはAppsScriptのスクリプトエディタ→ファイル→プロジェクトのプロパティにて確認可能です。

おそらく完了です。
APKを作成し、とりあえず動かしてみます。

起動した。
CALL GOOGLE APPS SCRIPT APIボタンを押下。

許可&許可。
認証アカウントを選択。(今回のAppsScriptを作成したアカウント)

読み込み中。

文字列が返ってきました。
おつかれさまです。

NFCでの読み取り部分を実装する

ここを参考にします。

AndroidManiFest.xmlにNFC関連のパーミッションを追加する。

<uses-permission android:name="android.permission.NFC" />

実装部分は後々書きます...

動かすまではできました。

カードをタッチして読み込み(結果が既に見えてしまっている...)

結果

スプレッドシートにも書き込み。

照会用データはこんな感じ。

A列にIdmを持っている。

AppsScript側はこんな感じ。

var icCardSheetUrl = 'シートURL';

function getIcCardData(idm) {
    var spreadSheet = SpreadsheetApp.openByUrl(icCardSheetUrl);
    var activeSheet = spreadSheet.getSheetByName("icdata");
    var lastRowNum = activeSheet.getLastRow();
    var valueList = activeSheet.getRange(1,1,lastRowNum,2).getValues();
    var map = {};
    for(var i = 0; i < valueList.length; i++){
        var childList = valueList[i];
        map[childList[0]] = childList[1];
    }
    var name = map[String(idm)];
    Logger.log(name);
    writeAttendanceData(name);
    return name;
}

function writeAttendanceData(name){
    var sheet = SpreadsheetApp.openByUrl(icCardSheetUrl);
    var activeSheet = sheet.getSheetByName('attendance');
    var lastRowNum = activeSheet.getLastRow();
    var range = activeSheet.getRange(lastRowNum+1,1,1,2);
    var today = new Date();
    var timeString = today.getHours()+":"+ today.getMinutes()+":"+ today.getSeconds();
    var values = [[name,timeString]];
    range.setValues(values);
}

Androidの画面のデザインを勉強すること。