Microsoft 系のあれこれ

港区の SIer で よくわからんことをしている人です。Xamarin 中心でした。(過去形)

SharePointにニュースが投稿されたらTeamsにPower Automateで通知する(投稿者アイコン画像付き)

ポイント

  • ニュース(ページ)が"変更されたら"じゃなくて"発行されたら"通知する
  • 投稿者のアイコン画像はData URI schemeを利用してAdaptive Cardに設定する

内容としてはタイトルの通りです。
上述の通り、いくつかポイントがあるので紹介します。

完成形

f:id:ShunsukeKawai:20200727141633p:plain

手順

準備(ListIDを控える)

SharePointのサイトすべてのサイトコンテンツからサイトのページの設定を開きます。
f:id:ShunsukeKawai:20200727132759p:plain
遷移先のURLから `List=` 以降の部分のIDを控えておきます。
f:id:ShunsukeKawai:20200727132650p:plain

Power Automateの定義

トリガー

Power Automateの作成画面から、トリガーとして「ファイルが作成または変更されたとき (プロパティのみ)」を選択し、サイトのアドレスには対象のサイトをドロップダウンから選択し、ライブラリ名には先ほど控えたListIDをカスタム値を入力から設定します。
フォルダーは `/SitePages` を指定します。
f:id:ShunsukeKawai:20200727134352p:plain
https://jmasystems.sharepoint.com/sites/TechJmas/SitePages/Forms/ByAuthor.aspx

条件の設定その1(ポイント①)

SharePointのニュースは書き始めた段階で下書き状態のファイルを保存してくれます。
非常に便利な機能ですが、今回の場合はこのままなにもせずにTeamsに通知すると書き始めや下書き保存のタイミングで何度も通知が来てしまいます。
そこで、条件により通知を絞り込みます。
Power Automateのアクションから「条件」を選択し、「昇格した状態」が「2」だったらという条件を追加します。
f:id:ShunsukeKawai:20200727135940p:plain
f:id:ShunsukeKawai:20200727135717p:plain
昇格した状態は英語だとPromotedStateっていうみたいです。
最初はバージョンの値に「.0」という文字列が含まれていたらって条件でやってましたが、こっちの方がきれいにできそうです。
参考:
PromotedState Enum (OfficeDevPnP.Core.Pages) | Microsoft Docs
sharepoint online - PromotedState of modern news pages is 0 after publishing - why? - SharePoint Stack Exchange

「2」以外の場合はまだ発行された状態ではないので通知はしないようにしています。

条件の設定その2

その他テンプレートやHome.aspx(ホーム画面)など、通知したくないファイルを条件に指定します。
f:id:ShunsukeKawai:20200727184043p:plain

ユーザーのアイコン画像取得(ポイント②-1)

SharePointから送られてきたデータにも更新者の画像URLは付いていますが、そのURLをTeamsの通知に設定してもアクセスすることができません。(実はWebブラウザでTeamを開いている場合は見れる)
f:id:ShunsukeKawai:20200727151437p:plain
そのため、更新者のメールアドレスから画像を取得する処理を追加します。
アクションの検索に「365」と入力し、「Microsoft 365 Users」を指定して「ユーザーの写真の取得 (V2)」を選択し、更新者のメールアドレスを設定します。
f:id:ShunsukeKawai:20200727152451p:plain
f:id:ShunsukeKawai:20200727150312p:plain

Teamsに投稿する

最後に今までの情報でTeamsに投稿します。

アクションをTeamsで検索して、「独自のアダプティブ カードをフローボットとしてチャンネルに投稿する(プレビュー)」(ここではなぜかチャネルじゃなくてチャンネルって表記だけど気にしない)を選択します。
f:id:ShunsukeKawai:20200727173137p:plain
チーム、チャネルをそれぞれ通知したい対象を選択して設定します。
f:id:ShunsukeKawai:20200727173454p:plain
メッセージに以下のようなJSONを設定します。 設定内容のポイントはその下に記載します。

{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.2",
    "body": [
        {
            "type": "Container",
            "items": [
                {
                    "type": "TextBlock",
                    "text": "記事が投稿or更新されました!",
                    "weight": "Bolder",
                    "size": "Medium"
                }
            ],
            "style": "default"
        },
        {
            "type": "Container",
            "items": [
                {
                    "type": "TextBlock",
                    "text": "@{triggerBody()?['Title']}",
                    "size": "ExtraLarge",
                    "weight": "Bolder",
                    "color": "Attention",
                    "wrap": true
                },
                {
                    "type": "TextBlock",
                    "text": "@{triggerBody()?['Description']}",
                    "wrap": true,
                    "size": "Medium",
                    "height": "stretch",
                    "fontType": "Default"
                }
            ]
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Image",
                            "style": "Person",
                            "url": "data:@{body('ユーザーの写真の取得_(V2)')?['$content-type']};base64,@{body('ユーザーの写真の取得_(V2)')?['$content']}",
                            "size": "Small"
                        }
                    ],
                    "width": "auto"
                },
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Container",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "weight": "Bolder",
                                    "text": "@{triggerBody()?['Editor']?['DisplayName']}",
                                    "wrap": true,
                                    "size": "Large",
                                    "spacing": "None"
                                }
                            ],
                            "height": "stretch",
                            "verticalContentAlignment": "Center"
                        }
                    ],
                    "width": "stretch"
                }
            ]
        },
        {
            "type": "TextBlock",
            "text": "",
            "wrap": true,
            "separator": true
         }
    ],
    "actions": [
        {
            "type": "Action.OpenUrl",
            "title": " 記事はこちら",
            "url": "@{triggerBody()?['{Link}']}",
            "style": "positive",
            "iconUrl": "https://user-images.githubusercontent.com/6369070/88062730-2db2f780-cba4-11ea-9c2f-27a823ab3088.png"
        }
    ]
}

JSONの内容は以下の公式デザイナーでいろいろいじって作成すると便利です。
Designer | Adaptive Cards

AdaptiveCard設定のポイント
  • 画像はData URI schemeを使用して設定 (ポイント②-2)

ユーザー写真取得処理の結果には以下のような値が入っています。画像のタイプと画像ファイルのバイナリデータです。
f:id:ShunsukeKawai:20200727182027p:plain
その内容をAdaptiveCardに設定するにはData URI schemeを使用してImageのURLに以下のように指定します。

data:@{body('ユーザーの写真の取得_(V2)')?['$content-type']};base64,@{body('ユーザーの写真の取得_(V2)')?['$content']}

Data URI schemeについては以下を参考にしてください。
Data URI scheme - Wikipedia

設定画面では以下のように見えると思います。
f:id:ShunsukeKawai:20200727182719p:plain
実際に設定されている内容はこんな感じです。

"url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wB~中略~A//Z",
  • 投稿内容と自動付加される境界に線を引く

現在、Power AutomateからTeamsに通知するフローボットを使用するとどうしても下記画像のようなテキストとリンクが自動で付加されてしまいます。
f:id:ShunsukeKawai:20200728005346p:plain
そのため、なんとなくわかりやすくしたいなということで空のテキストを置いてseparatorをtrueにして線を設定しています。

{
    "type": "TextBlock",
    "text": "",
    "wrap": true,
    "separator": true
}

線がないのとあるのじゃなんとなく印象が変わる気がしますよね。
変わんないじゃんと思っていても言わないでください。
f:id:ShunsukeKawai:20200728005913p:plain

  • ボタンに画像を設定する(小ネタ)

iconUrlに画像のURLを設定するだけですが、下記のURLを見てもらうとわかると思いますが、~github~となっています。
これはGitHubのどこのリポジトリでもいいのでIssue作成画面に行ってその画像をコピペやドラッグアンドドロップするとサーバーにあげて公開URLを生成してくれるので、とても便利です。(本来の使い方ではないでしょうが…)
Issueは保存する必要はなく、URLが生成されたらコピーして閉じちゃいましょう。消されたりして画像が見れなくなったことは今までありません。
(今後どうなるかはわかりません)

"actions": [
    {
        "type": "Action.OpenUrl",
        "title": " 記事はこちら",
        "url": "@{triggerBody()?['{Link}']}",
        "style": "positive",
        "iconUrl": "https://user-images.githubusercontent.com/6369070/88062730-2db2f780-cba4-11ea-9c2f-27a823ab3088.png"
    }
]


以上でおしまいです。

できてないこと

ニュースに設定されているサムネイルも通知に含めたかったんですが、うまくいかず。
やり方を知っている方いたら教えてください。

Microsoft Teams を使ってリモートワークでもチームの作業状況を把握する(with Power Automate & Excel)

~まえがき~

  • この記事の対象:
    • コロナウィルスなどの影響で急遽リモートワークの世界に異世界転生してきた Office 365 ユーザーの人たち

コロナウィルスの影響で様々な会社でリモートワークが推奨されるようになりました。
チーム全体が準備期間も満足に取れず、いきなりリモートになったことにより、あまりノウハウもなく、いろいろな問題がもうすぐ散見されることになるでしょう。
その最たる例として ”各人の作業の様子がわからない” みたいなことがあると思います。

よくあるフルリモートの会社さんみたいにWeb 会議ツールで常時繋いでいる、とかじゃなくチャットのみのやり取りの場合、メンバー間だけでなく、リーダーやマネージャーがメンバーの状況がわからないからどんどんモヤモヤが募ってお互い疲弊していきます。(Web 会議ツールで常時繋いでるのがいいと言っているワケではないです。今の世界情勢的に帯域の問題もあるし)
それが行きつくところまで行くと PC 操作ログを収集して稼働時間の管理をどうのこうの…という話になるのではないかと思います。そんな世界は嫌です。

そうなる前にちょっとでもチームメンバー間の心理的安全性の向上を図り、リーダーやマネージャーも全体の状況が把握することができる世界を目指しましょう。
細かいタスクの内容や進捗状況は各プロジェクトで利用している別の管理ツールでチケット管理等するとして、
本記事での目的は
メンバーを ”監視” することではなく、お互いに大した手間をかけずに作業の状況をリアルタイムで「こんなことやってるんだー」程度に知って&知ってもらってモヤモヤを少しでもなくそう
です。(そしてついでに作業報告書みたいなヤツも自動で作っちゃおう。みたいな。)
手間をかけないっていうのが重要だと思います。

よく Slack で使われている "分報" の作業状況の共有に特化したバージョンに近い内容です。
Slackで簡単に「日報」ならぬ「分報」をチームで実現する3ステップ〜Problemが10分で解決するチャットを作ろう | | Craftsman Software Inc.

Office 365 の世界でそれを実現するために Microsoft Teams と Power Automate を利用してみよう、ということです。
ベストな方法ではないかもしれませんし、それぞれの組織や個人によって向き不向きがあるかもしれません。他にもいいやり方があったら教えてください。
まえがきが長くなりましたが、以下から本編です。

本記事の内容でできること

  • Teams の一つのチャネルにメンバー全員の作業状況(例:XXXX画面, 設計書作成 など)が投稿できる(する)ようになる

f:id:ShunsukeKawai:20200409121735p:plain:h600
Teams 画面サンプル

  • 投稿内容を Power Automate で加工しつつ、Excel に登録し、メンバーごとのシートに作業ログを蓄積する
  • Excel でその日の作業時間の集計する

f:id:ShunsukeKawai:20200403145604p:plain
Excel サンプル

STEP1 : Teams にやっていることを書き込むチャネルを作ろう

専用のチャネルを作成します。
これやるだけでもだいぶ違います。(今回の例では「TaskLogger」というチャネルを作っています。)
やっていることを単語で簡潔に記載します。休憩とか終了とかもです。
ここのチャネルにメンバーがみんな投稿するので、だいたいのみんなの動きが把握できます。
Excel 連携とかいらないのであればこれだけやるでもいいでしょう。
なんとなく作業している内容が流れてくるだけでその場にいなくても空気感が共有できて安心できるのではないでしょうか。
いちいち書くのめんどくさいかも知れませんが、慣れてくると逆に「これをやるぞ!」と気合が入るので自分にとってもいい影響があります。

今回は後述する Excel への連携のために以下の半角のカンマ区切りのフォーマットで投稿するルールとしています。スレッドへの返信ではなくルートにメッセージを投稿します。(スレッドにすると他の人の投稿にいちいち通知来てしまうので。チャットでの通知コントロールは重要だと思います。
[category1], [category2], [startDate]

パラメーター 必須 説明
category1 作業カテゴリーその1
category2 作業カテゴリーその2
startTime タスク開始時間(指定しない場合は投稿時間になる)[HH:mm]形式

※ うっかり投稿忘れちゃったりすると思うので、後から投稿できるように任意でstartTimeがあります。

f:id:ShunsukeKawai:20200402174926p:plain
こんな感じ

STEP2 : 投稿したメッセージを Excel にため込もう

せっかく作業を投稿しているので、それを材料に作業報告書みたいな感じで一覧化すると進捗報告・管理とかで楽できるかもしれません。
なので Power Automate(旧 Microsoft Flow)を使って Excel に自動で流し込んでいきましょう。

STEP2-1 : Excel ファイルの作成

本項の内容を以下にテンプレートをアップしています。
1シート(1テーブル)に1人の実績がため込まれます。
"template" シートをコピーして使ってください。シートコピー後、テーブル名を上述のルールで変更してください。シート名も同じにしちゃうとわかりやすいでしょう。
https://1drv.ms/u/s!AteGEPv8p-wMgo0-c6NCfm-qwbX3SA?e=MvEJ7r

Excel を自分で作る場合は作成した Teams チャネルのファイルに Excel ファイルを作りましょう。

f:id:ShunsukeKawai:20200402181151p:plain:w300
Teams 上で作成
TaskLogs.xlsx としておきました。

STEP2-1-1 : Excel のテーブルに名前を付ける

Power Automate で Excel を更新できるのは Excel 内のテーブルに対してです。
後述する処理の中でテーブル名も可変にするためテーブル名は以下のルールで作成してください。(テーブル名には空白文字が設定できないため)
[TeamsのDisplayName(スペース抜き)]
例:川合俊介

f:id:ShunsukeKawai:20200403011615p:plain:w300
Teams の DisplayName はこれ
そしてテーブル名は Excel Onlile では編集できない(っぽい)ため、デスクトップ版の Excel でファイルを開いて テーブルデザインのところからテーブル名を編集してください。
f:id:ShunsukeKawai:20200403013045p:plain
テーブル名編集
テーブルには以下の列を定義しています。

作業日 開始時間 内容1 内容2

f:id:ShunsukeKawai:20200403090227p:plain
こんな感じ

シートとその中のテーブルはメンバー分作成してください。
1ファイルに人数分のシートがあり、そのシートに各個人用のテーブルがある状態です。
誰かひとりが全員分作るだけでよいです。
人数が多くてファイルを分割したい場合や1人1ファイルにしたい場合は Teams のチャネルから Excel ファイル、PowerAutomate の処理(本記事の内容すべて)を複数作成する必要があります。

STEP2-2 : Power Automate の処理作成

Power Automate の作り方を知りたい人以外は本項で作成できる構成を Zip ファイルにして置いておきますのでそれをインポートしてちょっと修正するだけで完成するので本項は飛ばしても大丈夫です。
飛ばす場合は下記リンクからジャンプしてください。
STEP2-3 : Power Automate を Zip ファイルからインポートする へジャンプ

Power Automate の作り方は以下の通りです。(長いです)
1. Teams からのメッセージを受ける
 まずは Teams に投稿されたらキックされるトリガーです。

種類 チャネルに新しいメッセージが追加されたとき(プレビュー)
設定 チーム 投稿するチーム
チャネル 投稿するチャネル
f:id:ShunsukeKawai:20200407150415p:plain:w500
2. 今の日付を変数に入れる
 Teams の投稿日時が UTC で来るので JST に変換して変数に入れておきます。
種類 変数を初期化する
設定 名前 logDate
種類 文字列
addHours(triggerBody()?['createdDateTime'],9,'MM/dd')
f:id:ShunsukeKawai:20200407150447p:plain:w500
3. 投稿されたカンマ区切りのメッセージ配列に格納
 半角カンマ区切りのメッセージ内容を分割して配列変数に格納します。
種類 変数を初期化する
設定 名前 messageArray
種類 アレイ
split(triggerBody()?['body']?['content'], ',')
f:id:ShunsukeKawai:20200407152219p:plain:w500
4. 内容1、内容2、開始時間の変数を初期化
 後で使うそれぞれの変数を初期化します。
種類 変数を初期化する
設定 名前 category1
種類 文字列
種類 変数を初期化する
設定 名前 category2
種類 文字列
種類 変数を初期化する
設定 名前 startTime
種類 文字列
f:id:ShunsukeKawai:20200407152315p:plain:w500

5. パラメーター数が3つ以下だったら
 一応パラメーター数のチェックをして FALSE だったら処理を中止してます。

種類 条件
設定 length(variables('messageArray'))
条件 次の値以下
3
f:id:ShunsukeKawai:20200407152947p:plain:w500
5-1. はいの場合
 ちょっと Power Automate の勉強も兼ねて無駄に複雑にしてしまったので全容をまとめて貼っときます。
f:id:ShunsukeKawai:20200407155651p:plain

5-1-1. パラメーターの配列の1番目をcaregory1に設定
 こいつは絶対入ってる前提で変数に設定します。

種類 変数の設定
設定 名前 category1
種類 文字列
trim(last(take(variables('messageArray'),1)))
f:id:ShunsukeKawai:20200408182207p:plain:w500
5-1-2. パラメーター数による処理分岐
 並列分岐を使ってます。分岐してそれぞれの処理をした後に合流を待機してくれるみたいです。
f:id:ShunsukeKawai:20200407155823p:plain
5-1-2-1. (並列分岐左側)パラメーター数が3つだったら
 配列が3つかで分岐します。
種類 条件
設定 length(variables('messageArray'))
条件 次の値に等しい
3
f:id:ShunsukeKawai:20200408182252p:plain:w500
5-1-2-1-1. はいの場合
5-1-2-1-1-1. パラメーターの配列の3番目をstartTimeに設定
 パラメーター数が3つだったら3番目(開始時間)を変数に設定します。
種類 変数の設定
設定 名前 startTime
種類 文字列
trim(last(take(variables('messageArray'),3)))
f:id:ShunsukeKawai:20200408183452p:plain:w500
5-1-2-1-2. いいえの場合
5-1-2-1-2-1. 投稿日時をstartTimeに設定
 パラメーター数が3つでなかったら(開始時間が設定されてなかったら)Teams への投稿日時を変数に設定します。
種類 変数の設定
設定 名前 startTime
種類 文字列
addHours(triggerBody()?['createdDateTime'],9,'HH:mm')
f:id:ShunsukeKawai:20200408183427p:plain:w500
5-1-2-1. (並列分岐右側)パラメーター数が2つ以上だったら
 配列が2つ以上かで分岐します。
f:id:ShunsukeKawai:20200408184812p:plain:w500
5-1-2-1-1. はいの場合
 パラメーター数が2つ以上だったら2つ目の値を変数に設定します。
種類 変数の設定
設定 名前 category2
種類 文字列
trim(last(take(variables('messageArray'),2)))
f:id:ShunsukeKawai:20200408184925p:plain:w500
5-1-2-1-2. いいえの場合
 なにもしません。
5-1-3. 表に行を追加
 SharePoint のドキュメントライブラリにある Excel ファイルのテーブルに行を追加する処理です。
種類 表に行を追加
設定 場所 Excel がある SharePoint サイト(= Teams のチーム)
ドキュメントライブラリ Documents(Teams のファイル保存先)
ファイル 作成した Excel を指定(Teams だと /チャネル/ファイル)
テーブル
※可変にするためにカスタム式に設定します
replace(replace(triggerBody()?['from']?['user']?['displayName'],' ',''),' ', '')
item
※コピペじゃできないので
それぞれの箇所を
@{} の中身を式で設定する
{
"作業日": @{variables('logDate')},
"開始時間": @{variables('startTime')},
"内容1": @{variables('category1')},
"内容2": @{variables('category2')}
}
f:id:ShunsukeKawai:20200408185652p:plain:w500

以上で Power Automate の処理作成は終わりです。
自分で作成した方は次項は飛ばして大丈夫です。
STEP2-4 : 動作確認 へジャンプ

STEP2-3 : Power Automate を Zip ファイルからインポートする

STEP2-3-1 : Zip ファイルのインポート

Excel テンプレートと同じフォルダに Power Automate の構成用 Zip ファイル が置いてあります。
https://1drv.ms/u/s!AteGEPv8p-wMgo0-c6NCfm-qwbX3SA?e=MvEJ7r

  • その Zip をダウンロードしておきます。
  • 以下に組織アカウントでサインインします。

Microsoft Power Automate | Microsoft Power Platform

  • 左のメニューから「データ」→「接続」→「新しい接続」を選択して接続情報を追加します。(すでに Teams の接続がある方は不要です。)

f:id:ShunsukeKawai:20200403103056p:plain:w300
新しい接続

f:id:ShunsukeKawai:20200403103203p:plain
Teams を選択

  • 確認画面が出てくるので「作成」を押した後認証画面が出てくるのでサインインします。

f:id:ShunsukeKawai:20200403103252p:plain:w500
作成を選択

  • Excel Online (Business) を選択します。(OneDrive の方じゃない)

f:id:ShunsukeKawai:20200403103434p:plain:w500
Business の方を選択

  • Teams と同じようにサインインします。
  • 左のメニューから「マイフロー」→「インポート」を選択します。

f:id:ShunsukeKawai:20200403101813p:plain:w300
インポートを選択

  • 先ほどの Zip ファイルをアップロードします。
  • アップロードに成功すると以下の画面が出てくるので「インポート時に選択する」を選択します。

f:id:ShunsukeKawai:20200407103912p:plain
インポート時に選択する を選択

  • 先ほど追加した接続情報が表示されているので選択して「保存」します。

f:id:ShunsukeKawai:20200403105014p:plain:w300
接続情報を選択

  • もう一つも同じように接続情報を指定して「保存」します。
  • 下記画面になったら「インポート」を選択します。(×と表示されていたり、私のメアドが表示されていますが、気にしないでください。)

f:id:ShunsukeKawai:20200403105448p:plain
インポートを選択

STEP2-3-2 : Power Automate の構成を修正
  • 前項でインポートが完了したら「フローを開く」を選択します。

f:id:ShunsukeKawai:20200403105801p:plain
フローを開く

  • 以下の画面が出てくるので Teams のところを選択します。

f:id:ShunsukeKawai:20200403110417p:plain
Teams を選択

  • わけわかんない文字列が設定されているため、一回消します。

f:id:ShunsukeKawai:20200403112531p:plain
×で消す

  • 使用するチームを選択します。

f:id:ShunsukeKawai:20200403112735p:plain
チームを選択

  • 同じように消してから使用するチャネルを選択します。

f:id:ShunsukeKawai:20200403112838p:plain
設定後

  • 一番下の「パラメーター数が3つ以下だったら」を選択します。

f:id:ShunsukeKawai:20200403113032p:plain
パラメーター数が3つ以下だったら を選択

  • 展開された条件の 一番下の Excel マークの「表に行を追加」を選択します。

f:id:ShunsukeKawai:20200403113141p:plain
Excel を選択

  • 「場所」、「ドキュメントライブラリ」を消してそれぞれ利用するファイルを再設定します。

f:id:ShunsukeKawai:20200403114026p:plain
再設定

  • 「ファイル」を再設定します。

f:id:ShunsukeKawai:20200403114415p:plain
ファイル設定
※ ファイルを再設定するとなぜか「item」が表示されなくなってしまうことがあります。その場合は一度、replace~と書いてあるところを消して、「カスタム値の入力」→「式」のところにreplace(replace(triggerBody()?['from']?['user']?['displayName'],' ',''),' ', '') を再設定すると「item」が復活します。
f:id:ShunsukeKawai:20200403114604p:plain
item が消えちゃった
f:id:ShunsukeKawai:20200403132717p:plain
テーブルを再設定する

  • 画面右上の「保存」ボタンで保存します。エラーがあったらここで表示されます。
STEP2-4 : 動作確認

Teams に投稿してみます。

f:id:ShunsukeKawai:20200403143720p:plain
投稿

しばらくすると Excel ファイルに登録されます。

f:id:ShunsukeKawai:20200403163132p:plain
Yeah!!!!!

STEP2-5 : 注意書きとか便利なところとか


※ Teams で投稿してからフローがキックされ、実際に Excel に値が登録するまで数分ラグがあります。気長に待ってください。みんなが一斉に投稿したりするともっと遅くなるかもしれません。

※ 今回の内容では半角カンマしか対応してません。

※ 内容1と開始時間だけ設定したい場合も内容2をブランクで [XXX, , 18:00] みたいに設定する必要があります。

※ 同じ作業とかで他からそのままコピペすると投稿が html 形式になっちゃって登録はできますが、タグとかもまとめて入っちゃいます。めんどくさいけど、手で入力するか、ctrl + v でなく ctrl + shift + vでテキストのみ貼り付けしてください

f:id:ShunsukeKawai:20200403143319p:plain
html になっちゃうので PlainText で

※ Office 365 に含まれるライセンスの場合、24時間で2,000回が上限(ほかにも使ってたら合計で)みたいです。
要求の制限と割り当て - Power Platform | Microsoft Docs

※ 投稿への返信ではフローがキックされないので、人の投稿(作業内容)で認識違いとかがあったり、気になったら返信することでその場で解消できます。便利。

※ このチャネルを頻繁に利用するハズなので、普段使ってる Teams のアプリとは別にブラウザでこのチャネルだけ開いとくとかをすると便利になるかもしれません。

STEP2-6 : Excel に集計関数を入れてその日の稼働時間を確認する

おまけです。
作業時間や案分を月末とかにまとめている人も多いと思うので
みんな大好き Excel 先生なので、各自好きにやったらいいと思いますが、一例として書いておきます。

f:id:ShunsukeKawai:20200403144903p:plain
集計例
=IF(A2=A3,B3-B2,0) でそのタスクの作業時間を出してます。
=IF(C2="終了",SUMIFS($F:$F,$A:$A,A2,$C:$C,"<>休憩"),"") で内容1が「終了」だったら同じ日の内容1の「休憩」の時間を除いた合計時間を出してます。

※ 深夜12時をまたぐ作業の場合には対応していないので、後で稼働日を直接修正してください。

~あとがき~

長くなってしまったw
今回いきなりリモートワークになって、てんやわんやでドタバタして、落ち着いたら「やっぱ会社にいないと仕事ができないね」って結論にならないように全世界大変な状況だけど、ポジティブに変革のチャンスと考えて楽しみながら少しでもみんなが幸せになれればよいなと思います。

本当に長くなってしましたが、以上です。

Azure Pipelinesのビルド完了をMicrosoft Teamsに通知するいくつかの方法

本記事はAzure DevOps Advent Calendar 2019 - Qiita 17日目です。
(蛇足ですが、前回の記事書いた後に「あ、そういえばAdventCalenderの季節じゃないか」と AzureDevOps を探したところ見つかったので本記事から参加してみました。)


前回の記事では Azure Pipelines で iOS の CI してみました。
shunsukekawai.hatenablog.com

せっかく CI したなら通知しないとね。ということで通知編です。
いくつかの方法とタイトルにあるのは諸事情(後述します)により、不採用となった方法があるためです。

それではやっていきましょう。

contents:

Teams のアプリから通知する

一番スマートかなと思う方法です。

Teams の会話のその他を選択します。

f:id:ShunsukeKawai:20191216123636p:plain
その他を選択
検索ボックスに「Pipeline」とでも入力します。
f:id:ShunsukeKawai:20191216123701p:plain
pipeだけで出てくる
Azure Pipelines を選択して Teams に追加します。
f:id:ShunsukeKawai:20191216125711p:plain
会話のメニューに追加されている
ボタンを選択します。機能を利用するには設定が必要みたいなので選択してサインインします。
f:id:ShunsukeKawai:20191216123732p:plain
サインイン
そうするとどこの Organization を見るか選択できるようになります。
f:id:ShunsukeKawai:20191216124240p:plain
どこを参照する?

が、ここで諸事情①です。
今回は所属する組織の Microsoft アカウントで Teams に入っています。ですが、AzureDevOps は顧客環境です。
顧客環境にもこちらの組織アカウントで権限が与えられているのですが、Teams 上だとその顧客環境は見えないみたいです。
そのためこの方法は不採用となりました。

ちなみに参照できる場合は Teams の会話で
@Azure Pipelines subscribe https://dev.azure.com/XXXXXXX/YYYYYYY/_build?definitionId=2
みたいな感じでメンションしてあげると
f:id:ShunsukeKawai:20191216125109p:plain
登録されたと返事がきます。

で、ビルドが完了すると通知が来ます。
f:id:ShunsukeKawai:20191216125235p:plain
シンプルでいい感じですね。

Pipeline にタスクとして追加する

Teams に追加できないとなると 自前でポストするヤツをゴニョニョしないといけないのか?と思いつつ、AzureDevOps の Marketplace を探してみました。

f:id:ShunsukeKawai:20191216130425p:plain
Pipeline の編集画面からタスク追加ボタンを押す
検索ボックスに「teams」と入れて検索し内容を見てみると、なんかよさげなのがありました。
Post To Office 365 Connector - Visual Studio Marketplace
最終更新が 2017 年とかだけど、入れてみましょう。(外部アプリは自己責任で)
f:id:ShunsukeKawai:20191216131126p:plain
teams で検索して Post To Office 365 Connector を選択

f:id:ShunsukeKawai:20191216131510p:plain
Get it free を選択
そうするとインストール先の Organization を選択する画面が出てきます。(Teams のアプリと違って顧客環境の Organization も見れる)
顧客環境の管理者に許可が必要みたいなので、あと回しにして自分の環境に一回インストールしてみます。
f:id:ShunsukeKawai:20191216131653p:plain
顧客環境の管理者に許可が必要みたい
f:id:ShunsukeKawai:20191216132042p:plain
自分の環境だと当然インストールできる

その後、もう一度Pipeline の編集画面からタスク追加ボタンを押し、「post」と入力すると先ほど追加したヤツが出てきます。

f:id:ShunsukeKawai:20191216132220p:plain
タスク追加に出てくる
追加するとこんな感じの設定画面です。
f:id:ShunsukeKawai:20191216132424p:plain
Post To Office 365 Connector の設定画面
WebHook の URL は Teams で取得します。
チャネルのメニューからコネクタを選択します。
f:id:ShunsukeKawai:20191216132737p:plain
Teams のチャネルのメニューからコネクタを選択
Incoming Webhook を追加します。
f:id:ShunsukeKawai:20191216132947p:plain
Incoming Webhook を追加
名前と画像(任意)を設定して完了すると URL が生成されるので、コピーして Pipeline 側の Webhook URL に貼り付けます。
f:id:ShunsukeKawai:20191216133327p:plain
名前と画像(任意)を設定して完了すると URL が生成される

その他の設定は Markdown と build variables も使えるみたいので
Title は
$(Build.DefinitionName) build $(Build.BuildId) complete
としました。
Message は前回も参考にさせていだたいた記事をベースに、

* RequestedFor : $(Build.RequestedFor)
* Environment:AdHoc
* Configuration:$(Configuration)
* Certificate:$(APPLE_CERTIFICATE_SIGNING_IDENTITY)
* Provisioning Profile:$(APPLE_PROV_PROFILE_UUID)
* Branch:$(Build.SourceBranch)
* Last Commit ID:$(Build.SourceVersion)  
* Last Commit Comment:$(Build.SourceVersionMessage)  

* Release Note:$(ReleaseNote)  

[result link](https://dev.azure.com/XXXXXXX/YYYYYYY/_build/results?buildId=$(Build.BuildId))

としました。

f:id:ShunsukeKawai:20191216134214p:plain
完成形
その他の情報入れたい場合は下記リンク先を参照ください。
Predefined variables - Azure Pipelines | Microsoft Docs

こいつを Pipeline の最後に追加してあげて実行してみます。
すると Teams に通知が決ます。Commit のコメントが複数行だとちょっと表示がズレますがまぁいいでしょう。

f:id:ShunsukeKawai:20191216135648p:plain
Teams 通知

よし、これで行こう。と思った矢先、このタスクを追加するのに顧客の承認が必要で、かつ、このアプリをインストールしてもセキュリティに影響がないことを説明する必要があると言われました。
えぇ…と思いましたが、面倒なことには首を突っ込みたくないのでこの方法も不採用となりました。

メールで通知する

一番簡単な方法です。
正直負けた気がします。
Teams にはチャネルに対してメールアドレスを設定することができます。
そのメール宛に Pipeline の完了を通知する方法です。
Teams のチャネルの設定からメールアドレスを取得します。

f:id:ShunsukeKawai:20191216140302p:plain
チャネルのメールアドレスを取得
そのアドレスを控えておいて AzureDevOps の Project Settings ⇒ Notifications ⇒ New subscription を選択します。
f:id:ShunsukeKawai:20191216140954p:plain
New subscription を選択
ビルド完了時の設定をします。
f:id:ShunsukeKawai:20191216141648p:plain
A build completes を選択
Deliver to に Custom email addressを選択して先ほどに Teams のメールアドレスを設定します。
条件のところにDefinition nameを選択して対象の Pipeline の名前を選択します。2環境以上の場合は or でつなぎましょう
f:id:ShunsukeKawai:20191216141544p:plain
通知条件の設定

で、ビルドを実行するとメール経由で Teams に通知が来ます。

f:id:ShunsukeKawai:20191216142423p:plain
メールアドレス宛に通知が来る

なんとなく美しくないですが、残念ながら今回はこの方法を採用しました。

AzureDevOpsとAppCenterでiOSアプリをCI/CDする

ほぼほぼ参考にさせていただいたこちらのサイト(iOSアプリのCI/CD〜Azure Pipelines編〜 - Qiita)の通りですが、特殊な箇所やハマったところがいくつかあったので、残しておきます。
iOS 開発ナニモワカラナイので、誤りがあったらご指摘ください。

contents:

AzureDevOps のエディター

YAML とかよくわかんないので GUI で設定できるようにパイプライン作成時に以下を選択して作ります。
f:id:ShunsukeKawai:20191213144454p:plain

XCode のバージョン指定

今回はやんごとなき事情で XCode の10.1 をビルドに使いたかったのでバージョン指定しました。
「Specify path」を選択して Path に/Applications/Xcode_10.1.appと入力します。

f:id:ShunsukeKawai:20191213140544p:plain
XCode Build タスクの Xcode version

バージョンに指定する値は下記サイトに記載があります。(対象のOSのREADMEになにがそのOSに入っているかが書いてある)
https://github.com/actions/virtual-environments/blob/master/images


署名

冒頭で紹介した参考サイトにも記載されていますが、署名のところで色々うまくいかなかったです。
結局参考サイトと同じ以下の設定にしました。

f:id:ShunsukeKawai:20191213150922p:plain
XCode Build タスクの Signing & provisioning

マニュアル署名だと、すべてのプロジェクトに署名しようとしてしまい Pod で参照しているライブラリに対して does not support provisioning profiles. と以下のエラーが全ライブラリに対して出まくります。

❌  error: R.swift.Library does not support provisioning profiles. R.swift.Library does not support provisioning profiles, but provisioning profile XXXXXXXXXXXXX has been manually specified. Set the provisioning profile value to "Automatic" in the build settings editor. (in target 'R.swift.Library')
** ARCHIVE FAILED **
##[error]Error: /usr/bin/xcodebuild failed with return code: 65
##[section]Finishing: Xcode build

そのため、参考サイトと同じ様に Podfile の末尾に追記しました。

post_install do |installer|
  installer.pods_project.build_configurations.each do |config|
    config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = ''
    config.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
    config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
  end
end

そしてこれだけでなく、今回の案件では Dynamic Library を使用していて、そこでも同じエラーが発生していました。
project.pbxprojを適当なエディターで開いてライブラリの対象 Configuration の buildSettings に以下を追記します。(たぶん XCode でやればいいんだけど、Windows だけで作業してたため直編集しちゃった…)

CODE_SIGNING_ALLOWED = NO;
CODE_SIGNING_REQUIRED = NO;
PROVISIONING_PROFILE = '';
PROVISIONING_PROFILE_SPECIFIER = '';

以上でなんとかビルドが成功するようになりました。

dSYM を AppCenter にアップロードする

AppCenter でテストアプリを配布するのは参考サイトの通りですが、クラッシュログ分析のため、シンボルファイルを AppCenter にアップロードする設定を追加しました。

デフォでできている Copy Files to: $(build.artifactstagingdirectory)のタスクをクローンします。
f:id:ShunsukeKawai:20191213164644p:plain
Target Folder の箇所を$(build.artifactstagingdirectory)/dSYMsに変更します。
Contents を**/*.dSYM/**に変更します。

f:id:ShunsukeKawai:20191213164942p:plain
Copy Files設定後
続いてPublish Artifactsのタスクもクローンして、先ほど設定した$(build.artifactstagingdirectory)/dSYMsを Path to publish に設定します。
Artifact name は適当にdSYMsとかにしておきましょう。
f:id:ShunsukeKawai:20191213171724p:plain
Publish Artifacts設定後
そして最後に AppCenter の Deploy タスクの Symbols のところの dSYM path に$(build.artifactstagingdirectory)/dSYMsを設定します。
そうすると自動でアップロードしてくれるようになります。
f:id:ShunsukeKawai:20191213171822p:plain
Deploy **/*.ipa to Visual Studio App Center 設定後
デプロイ完了後、AppCenter のシンボルの箇所を見るとアップロードされています。
f:id:ShunsukeKawai:20191213172136p:plain
AppCenter にアップされてる

Yammer の投稿を Flow を使ってどこかに連携する時に投稿者の氏名を取得する

Microsoft Flow のテンプレートに以下がありますが、投稿者の氏名が取れません。(sender_id なるものはある)

Yammer グループの新しいメッセージを Slack チャネルに投稿する | Microsoft Flow

Yammer からのメッセージの中身

{
  "id": 384547852050432,
  "sender_id": 2955093,
  "replied_to_id": null,
  "created_at": "2019/10/24 04:37:18 +0000",
  "network_id": 146187,
  "message_type": "update",
  "sender_type": "user",
  "url": "https://www.yammer.com/api/v1/messages/384547852050432",
  "web_url": "https://www.yammer.com/XXXXXXXX/messages/384547852050432",
  "group_id": 11132715008,
  "body": {
    "parsed": "test",
    "plain": "test",
    "rich": "test"
  },
  "thread_id": 384547852050432,
  "client_type": "Web",
  "client_url": "https://www.yammer.com/",
  "system_message": false,
  "direct_message": false,
  "chat_client_sequence": null,
  "language": "et",
  "notified_user_ids": [],
  "privacy": "private",
  "attachments": [],
  "liked_by": {
    "count": 0,
    "names": []
  },
  "content_excerpt": "test",
  "group_created_id": 11132715008,
  "topics": []
}

投稿者の氏名が欲しい場合は Yammer のトリガーと Action(今回だと Slack)の間にユーザー情報取得を噛ませてあげる必要があります。
f:id:ShunsukeKawai:20191024142808p:plain
追加するアクションで「Yammer」で絞り込んで⇒「ユーザー情報詳細を取得する(プレビュー)」を選択します。(プレビューだけどとりあえず動いてるから大丈夫でしょう)
f:id:ShunsukeKawai:20191024143004p:plain
ユーザーID のところに元メッセージの「メッセージ一覧 メッセージ送信者」を選択して設定してあげます。
f:id:ShunsukeKawai:20191024143257p:plain
後は連携先のメッセージ内容に入れてあげるだけで完了です。
f:id:ShunsukeKawai:20191024143530p:plain
Yammer から投稿してみます。
f:id:ShunsukeKawai:20191024143817p:plain
成功です!
f:id:ShunsukeKawai:20191024143741p:plain

Xamarin.Forms 製の iOS アプリから SQLite のDB ファイルをエクスポートする機能を追加する

内部で使うとかで適当に作ったアプリのDBファイル内のデータが確認したくなりました。
ちゃんとサーバーにデータを保存すればいい

まとめ

  • Xamarin.Essentials.Share を使ってアプリ内部データを取り出して共有するのが簡単だった。
  • Xamarin.Essentials Ver.1.1.0 の時点ではファイル共有は Preview です。

サンプルプロジェクト

公式ドキュメントに SQLite のサンプルがあるので、そいつに機能追加します。
Xamarin.Forms のローカル データベース - Xamarin | Microsoft Docs
上のドキュメントのリンク先から Zip でダウンロードできます。
Todo - Xamarin

サンプルプロジェクトに DB 出力ボタンを追加する

TodoListPage.xaml に ToolbarItem を追加して OnExportDbFile イベントを追加します。

<ContentPage.ToolbarItems>
    <ToolbarItem Clicked="OnItemAdded" Text="+">
        <ToolbarItem.Icon>
            <OnPlatform x:TypeArguments="FileImageSource">
                <On Platform="Android, UWP" Value="plus.png" />
            </OnPlatform>
        </ToolbarItem.Icon>
    </ToolbarItem>
    <ToolbarItem Clicked="OnExportDbFile" Text="Share">
        <ToolbarItem.Icon>
            <OnPlatform x:TypeArguments="FileImageSource">
                <On Platform="Android, UWP" Value="plus.png" />
            </OnPlatform>
        </ToolbarItem.Icon>
    </ToolbarItem>
</ContentPage.ToolbarItems>

Xamarin.Essentials を NuGet から追加

有機能を利用するため、Xamarin.Essentials を追加します。
f:id:ShunsukeKawai:20190604180224p:plain
Xamarin.Essentials に関しては公式ドキュメントを参照ください。
Xamarin.Essentials:共有 - Xamarin | Microsoft Docs

スタートアップのコードに宣言を追加する

Xamarin.Essentials Ver.1.1.0 (2019/06/04 時点)ではファイル共有はまだ Preview のため、明示的にアプリのスタートアップに宣言が必要みたいです。

ExperimentalFeatures.Enable(ExperimentalFeatures.ShareFileRequest);

App.cs のコンストラクタに上記宣言を追加します。

public App()
{
    ExperimentalFeatures.Enable(ExperimentalFeatures.ShareFileRequest);

    Resources = new ResourceDictionary();
	Resources.Add("primaryGreen", Color.FromHex("91CA47"));
	Resources.Add("primaryDarkGreen", Color.FromHex("6FA22E"));
    var nav = new NavigationPage(new TodoListPage());
	nav.BarBackgroundColor = (Color)App.Current.Resources["primaryGreen"];
	nav.BarTextColor = Color.White;

	MainPage = nav;
}

DB ファイルパス取得のメソッド追加

どのファイルを共有するかをパスで指定するため、TodoItemDatabase.cs にパス取得用メソッドを追加します。

public string GetDbPath() => database.GetConnection().DatabasePath;

ボタンの処理に共有処理を追加する

これで準備完了なので、TodoListPage.xaml.cs のボタン押下時のイベントに出力処理を追加します。

private async void OnExportDbFile(object sender, EventArgs e)
{
    await Share.RequestAsync(new ShareFileRequest
    {
        File = new ShareFile(App.Database.GetDbPath())
    });
}

アプリを起動して確認する

※ ファイル共有はシュミレーターだと、共有先の選択肢がないため、実機で確認しています。
適当にデータを追加した後に、「Share」ボタンを押します。
f:id:ShunsukeKawai:20190604190921p:plain
共有メニューが出てきました。簡単ですね。
f:id:ShunsukeKawai:20190604190959p:plain

実際にDBの中身見てみる

いろんな選択肢がありますが、一番手っ取り早そうなのは AirDrop でしょうか。
事前に MacSQLite のDB ファイルを参照できるアプリをインストールしておきます。
Downloads - DB Browser for SQLite

共有メニューの AirDrop 先から選択して、Mac 側で受け入れます。
そのファイルを開くと…
f:id:ShunsukeKawai:20190604190152p:plain
生データが参照できます!じゃーん。

今回のサンプルは以下にアップしてあります。
GitHub - shunsuke-kawai/SQLiteExportSample

Azure Storage Explorer 上で Cosmos DB への操作した時の消費 RU とかを Fiddler で確認したい

自分用めも

Azure Storage Explorer で CosmosDB への追加、更新、削除とかの RU の消費を確認したい時には Azure Storage Explorer のプロキシ設定を変更すると Fiddler でキャプチャできるようになる
Httpsのキャプチャ設定は事前にしておく)

URL : https://127.0.0.1
Port : 8888
Fiddlerのデフォルト

f:id:ShunsukeKawai:20190204214620p:plain
Edit→Configure Proxy
f:id:ShunsukeKawai:20190204214721p:plain
Proxy Settings

こんな感じで確認できる

f:id:ShunsukeKawai:20190204215356p:plain
Response

Xamarin.FormsでiOSのスプラッシュの背景色が意図した色にならない

あるアプリでテーマカラーを以下のような色にしたかったのですが、スプラッシュ画面が意図した色にならなかったため、その対応方法です。
「Xamarin.Formsで」と記載されてるのは同じような問題が Mac で普通に iOS のアプリを作っても発生するのかわからなかった(知らない)ので、保険として。
f:id:ShunsukeKawai:20180926173433p:plain

iOS でのスプラッシュには Storyboard を使用しています。

まとめ

  • Visual Studio で Storyboard は編集しない
  • ColorSpace は sRGB

現象再現手順

WindowsVisual Studio で Storyboard の背景色を変更します。
f:id:ShunsukeKawai:20180926181720p:plain

アプリを起動します。
↓スプラッシュ
f:id:ShunsukeKawai:20180926182504p:plain:w400

はい、その次の画面で同じ色を背景にしたログイン画面が出てくるのですが、比べてみましょう。
↓ログイン画面
f:id:ShunsukeKawai:20180926182646p:plain:w400

違いますね。

色々調べてみるとXamarin のリポジトリにも Issue があがってました。
Xamarin の問題じゃないぞ、とクローズされてますが、解決方法が書いてありました。
iOS Storyboard Launch Screen color issue · Issue #1750 · xamarin/Xamarin.Forms · GitHub

This particular issue does look like a mismatched colorspace. We don't currently expose an easy way to alter the colourspace, but it is on the roadmap.

For now can you can open your storyboard in Xcode and access the colorspace selector like this: https://recordit.co/JAVdR1FHjh . If you want things to match you will have to use the same RGB values and the same colorspace for both controls. There is some more information here about handling colorspaces: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/

colorspace が違うから、と書いてあるようです。
ということで対応します。

対応方法

先ほど編集した Storyboard をエディターで開くと色を定義している箇所が以下の様になっています。

<color key="backgroundColor" red="0.84313725490196079" green="0.23137254901960785" blue="0.00784313725490196" alpha="1" colorSpace="calibratedRGB"/>

ここの colorSpace="calibratedRGB" が悪いヤツみたいです。

MacXcode で対象の Storyboard を開き、色を変更するウィンドウの歯車マークを選択して sRGB ~~ を選択して、再度正しい色の値を設定します。
f:id:ShunsukeKawai:20180926185849p:plain

編集した Storyboard は以下の様になっています。

<color key="backgroundColor" red="0.84313725490196079" green="0.23137254901960785" blue="0.0078431372549019607" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>

colorSpace="custom" customColorSpace="sRGB"の部分ですね。

この部分の変更を元のプロジェクトにしてやって再度アプリを起動します。
f:id:ShunsukeKawai:20180926191942p:plain:w400

ちゃんと意図した色になりました!!

この Storyboard を再度 Visual Studio の Interface Builder で編集するとcolorSpace="calibratedRGB"に戻ります(汗
そのため、今後は Storyboard を Visual Studio で編集しないようにしましょうっとw

補足

  • Visual Studio for Mac でも同じ現象が再現しました。
  • GenericRGB はもう使うなって Apple は言ってる?

kCGColorSpaceGenericRGB - Core Graphics | Apple Developer Documentation

  • ネイティブ開発でも同じなのかな?

InterfaceBuilderで色を設定するときはcolorSpaceに気をつけよう - Qiita

GitHubの組織へのメンバー変更をMicrosoft Teamsに通知する(by Microsoft Flow)

ちょっと手順が面倒だったのでまとめておきます。
GitHub の Organization で会社のソース管理諸々をしているのですが、メンバーの変更が流動的だったりで変更の内容を Microsoft Teams に通知したかったのです。
Microsoft Flow を使って連携します。
今回実現したいことは

  • GitHub の Organization にメンバーが招待された、削除された時に通知がしたい

です。

目次

Microsoft Teams にコネクタを追加する

まずは通知先の Teams のチャンネルにコネクタを追加します。
f:id:ShunsukeKawai:20180719191506p:plain
表示されたコネクタ一覧から Incoming Webhook を選択します。
f:id:ShunsukeKawai:20180719191648p:plain
適当な名前と画像を設定して作成すると URL が生成されるので、それを控えておきます。
f:id:ShunsukeKawai:20180719191954p:plain

Microsoft Flow にトリガーを追加する

トリガーの作成

今回はマッシュアップ的なサービスである Microsoft Flow を利用して連携します。
プロセスとタスクの自動化 | Microsoft Flow
様々なテンプレートが用意されていますが、新規作成します。(以下の URLから)
https://japan.flow.microsoft.com/manage/flows/new
トリガーとなるコネクタ一覧から「要求」というのを選択します。(もうちょっと名前どうにかならんのかな…)
f:id:ShunsukeKawai:20180719193024p:plain
表示されたトリガーから「要求 - HTTP 要求の受信時」というのを選択します。(もうちょっと名前どうにかならんのかな…2)
f:id:ShunsukeKawai:20180719193614p:plain
次の画面で「サンプルのペイロードを使用してスキーマを生成する」を選択します。
f:id:ShunsukeKawai:20180719194732p:plain
その画面のまま次の手順に進みます。

GitHub の Webhooks のペイロードからスキーマを設定

GitHub の Organization 関連の Webhook の内容は以下の GitHub 公式ドキュメントを参考にします。
https://developer.github.com/v3/activity/events/types/#organizationevent
そこの Webhook payload example に記載されてる JSON を丸ごとコピーします。
https://developer.github.com/v3/activity/events/types/#webhook-payload-example-17
この JSON からスキーマが作成され、後で作成するアクションに対して簡単に埋め込めるようになります。
※ 上記公式サンプルは action が member_invited の場合ではないので一旦コピーした JSON をなにかエディターに貼り付けて action と membership の間に以下の invitation 部分を追加します。

  "action": "member_added",

    "invitation": {
        "id": 999999,
        "node_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "login": null,
        "email": "XXXXX@XXXX.co.jp",
        "role": "direct_member",
        "created_at": 9999999999,
        "inviter": {
            "login": "shunsuke-kawai",
            "id": 6369070,
            "node_id": "MDQ6VXNlcjYzNjkwNzA=",
            "avatar_url": "https://avatars2.githubusercontent.com/u/6369070?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/shunsuke-kawai",
            "html_url": "https://github.com/shunsuke-kawai",
            "followers_url": "https://api.github.com/users/shunsuke-kawai/followers",
            "following_url": "https://api.github.com/users/shunsuke-kawai/following{/other_user}",
            "gists_url": "https://api.github.com/users/shunsuke-kawai/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/shunsuke-kawai/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/shunsuke-kawai/subscriptions",
            "organizations_url": "https://api.github.com/users/shunsuke-kawai/orgs",
            "repos_url": "https://api.github.com/users/shunsuke-kawai/repos",
            "events_url": "https://api.github.com/users/shunsuke-kawai/events{/privacy}",
            "received_events_url": "https://api.github.com/users/shunsuke-kawai/received_events",
            "type": "User",
            "site_admin": false
        }
    },

   "membership": {
    …

編集した JSON を先ほどの Flow のページに貼り付けるとスキーマを作成してくれます。(左のメッセージは「わかりました」で OK です。)
f:id:ShunsukeKawai:20180719205121p:plain

Microsoft Flow に Teams に通知するアクションを追加する

アクションの作成

先ほど作成したトリガーの下に「新しいステップ」というのがあるので選択して「条件の追加」を選択します。
f:id:ShunsukeKawai:20180719205240p:plain
「値の選択」にフォーカスを当てると以下の画面が出てきます。先ほどの JSON から作成してくれたスキーマです。
f:id:ShunsukeKawai:20180719205351p:plain
今回は招待されたらという条件を追加したいので「action」を選択して、GitHub 公式ドキュメントにあった値である「member_invited」を設定します。
f:id:ShunsukeKawai:20180719205611p:plain
続いてその条件が True だった時に行うアクションを設定します。
f:id:ShunsukeKawai:20180719205628p:plain
アクションの追加から「HTTP」を選択します。
f:id:ShunsukeKawai:20180719205719p:plain
表示されたアクションから「HTTP - HTTP」を選択します。
方法に「POST」URI に Teams でコネクタを作成した時に生成された URL を設定します。
f:id:ShunsukeKawai:20180719210047p:plain

本文の設定

本文の設定内容については以下の記事を参考にさせていただきました。
Microsoft Flow を使って Microsoft Teams へ投稿する(続編) | idea.toString();
以下のような JSON に編集しました。後程設定するので value が空の箇所があります。

{
    "@@type": "MessageCard",
    "@@context": "http://schema.org/extensions",
    "themeColor": "ff4fbc",
    "summary": "概要",
    "sections": [
      {
        "activityTitle": "GitHubにメンバーが招待されました。",
        "facts": [
          {
            "name": "担当者",
            "value": ""
          },
          {
            "name": "追加メンバー",
            "value": ""
          }
        ],
        "markdown": true
      }
    ],
    "potentialAction": [
      {
        "@@type": "ActionCard",
        "name": "GitHub メンバー一覧",
        "actions": [
          {
            "@@type": "OpenUri",
            "name": "GitHub メンバー一覧",
            "targets": [
              {
                "os": "default",
                "uri": "https://github.com/orgs/JMASystems/people"
              }
            ]
          }
        ]
      }
    ]
  }

それを Flow の「本文」に貼り付けます。
担当者の value の値を選択した状態で(見えない箇所にありますが)右下に出てくる動的なコンテンツの「login」を選択します。
※ login が複数ありますが、選択して設定した後にマウスカーソルを当てると階層が表示されるのでそこで正しいかを確認してください。(ここは「triggerBody()?['sender']?['login']」となっていれば OK)
  面倒な場合は動的なコンテンツでなく、式のタブから直接「triggerBody()」を選択して階層を記載しても大丈夫です。
f:id:ShunsukeKawai:20180719223113p:plain
続いて追加メンバーも同じ様に value の値を選択した状態で「email」を選択します。
そうすると、招待をした人の GitHub アカウント ID、招待された人のメールアドレスが埋め込まれます。

削除時のアクションも追加する

先ほどは招待時だったので条件の「いいえの場合」にさらに条件を追加します。
f:id:ShunsukeKawai:20180719223724p:plain
条件は action が「member_removed」だったらです。
f:id:ShunsukeKawai:20180719223804p:plain
招待時と同じ様に、HTTP のアクションを追加して本文を加工します。
設定した内容は以下の通りです。削除された時は GitHub のアカウント ID が取れるのでそれを設定しています。

{
  "@@type": "MessageCard",
  "@@context": "http://schema.org/extensions",
  "themeColor": "bcff4f",
  "summary": "概要",
  "sections": [
    {
      "activityTitle": "GitHubからメンバーが削除されました。",
      "facts": [
        {
          "name": "担当者",
          "value": "@{triggerBody()?['sender']?['login']}"
        },
        {
          "name": "削除メンバー",
          "value": "@{triggerBody()?['membership']?['user']?['login']}:@{triggerBody()?['membership']?['user']?['html_url']}"
        }
      ],
      "markdown": true
    }
  ],
  "potentialAction": [
    {
      "@@type": "ActionCard",
      "name": "GitHub メンバー一覧",
      "actions": [
        {
          "@@type": "OpenUri",
          "name": "GitHub メンバー一覧",
          "targets": [
            {
              "os": "default",
              "uri": "https://github.com/orgs/JMASystems/people"
            }
          ]
        }
      ]
    }
  ]
}

ここまでで Flow の設定は終わりです。(今回は追加時にはなにもしないとしています。)
保存をするとトリガーとして作成した「HTTP 要求の受信時」の「HTTP POST の URL」の箇所に URL が生成されているのでコピーします。
f:id:ShunsukeKawai:20180719224824p:plain

Github に Webhooks を追加する

GitHub の Organization の Settings から「Webhooks」を選択します。
f:id:ShunsukeKawai:20180719224938p:plain
「Add webhook」を選択して、「Payload URL」に Flow で生成された URL を貼り付けます。
「Content type」は「application/json」を選択してください。
f:id:ShunsukeKawai:20180719225352p:plain
Which events would you like to trigger this webhook? のところで「Let me select individual events.」を選択します。
するとイベントが一覧で出てくるので今回は「Organizations」を選択します。
f:id:ShunsukeKawai:20180719225454p:plain
「Add webhook」ボタンを押して完了です。

動作確認

実際にメンバーを招待してみます。
すると Teams に通知が来ました!
f:id:ShunsukeKawai:20180719225829p:plain
削除してみます。同じ様に通知が来ます!
f:id:ShunsukeKawai:20180719225949p:plain

完成!

※ 同じユーザーを招待/削除を繰り返すと GitHub の招待 Webhook が飛ばないみたいです。うまく行かない場合は GitHub の Webhook の履歴、Flow の履歴を追ってみるとどこが動いてる/動いてないは分かると思います。

de:code 2018 イベントアプリ振り返り

5/22,23 で開催された de:code 2018 に公式イベントアプリを提供しました。
de:code (decode) 2018 | 開発者をはじめとする IT に携わる全てのエンジニアのためのイベント

自分用振り返りをまとめておきます。

公式イベントアプリ機能

マイクロソフトさんのイベントアプリ開発は今回で5回目です。今までと同様に Xamarin.Forms で作成しています。
毎回新たな試みが追加されますが、今回の de:code では細かなブラッシュアップとともに以下が追加/更新されました。

セッション聴講者属性

各セッションの参加者がどんな領域を担当しているか、主に使用しているサービス、言語を表示するようにしました。
f:id:ShunsukeKawai:20180524173611p:plain:w400

会場マップの混雑状況表示

日本システムウェア 様の CityVision*1 というサービスと連携して会場の混雑状況を表示できるようになりました。
f:id:ShunsukeKawai:20180524173739p:plain:w400
f:id:ShunsukeKawai:20180524173806p:plain:w400

スタンプラリー

デンソーコミュニケーションズ 様の Sifty*2 というサービスと連携してスタンプラリーを実装しました。
f:id:ShunsukeKawai:20180524173922p:plain:w400
f:id:ShunsukeKawai:20180524173936p:plain:w400

お知らせ

今までのアプリでは何か参加者の皆様にお知らせをしたい時、Push 通知を行っていましたが、Push するほどでもない場合もあったり、通知を許可していない方、読む前に消してしまった方がお知らせを見れなくなってしまうためお知らせ画面を追加しました。まぁ今までない方が変だったと思います。

その他機能は私が担当したセッション資料の前半に記載してあります。

www.slideshare.net

よくあったお問い合わせ

(全部書いていいのかわかりませんが) よくあるお問い合わせとして以下がありました。

アプリにサインインできない

Microsoft アカウントには組織、個人のアカウントがあり、かつそれが同じメールアドレスの場合、Web の申し込みサイトでは(私たちの開発ではないので正確にはわからないですが)試してみたところ自動的に個人アカウントでのサインインになってしまう挙動を見せていました。
そのため、参加者の方は組織でサインインしているつもりでも個人で入ってしまっていて、アプリからも組織を選択するとサインインできない。というケースが多かったです。
現在、Microsoft アカウントを組織と個人が同一のメールアドレスで作成することはできなくなっていますが*3前はできていたので(私もアカウント両方持ってます)、そういう方がいらっしゃったようです。(同一メールアドレスで作成する抜け道もあるみたいですが、ここでは言及は避けます。)

スタンプラリーができない

スタンプラリーを撮影するボタンを押すとアプリが落ちる
イベントアプリでは Visual Studio App Center を利用して Crash のログを見れるようにしているのですが、そのログを見ると以下のようなログがあがってました。
f:id:ShunsukeKawai:20180524174759p:plain
f:id:ShunsukeKawai:20180524174826p:plain
発生している端末は HUAWEI の PXX 系ばかりです。私の端末は HUAWEI Mate 9 なのですが、正常に動いています。

カメラ使用に Xam.Plugin.Media*4 を利用していたのですが、そのプラグインに以下の Issue があがっていて、HUAWEI の端末に問題があったみたいです。(絶対これが原因かは断言できない気がしてきたけど…)
IllegalArgumentException on Huawei devices · Issue #496 · jamesmontemagno/MediaPlugin · GitHub

アプリで利用している Stable 版のプラグイン(Ver.3.1.3)には本 Issue の対応はまだ入っておらず、そのままアプリのバグとなってしまいました。該当された方、申し訳ありませんでした。

その他

アンケートが表示されない系は受付時の参加者パスの ID との紐づけがうまくできていないなどらしいです。ぐるぐるがなかなか終わらない系はサーバーサイドが重くなっていた、ネットワークが遅い等でアプリ側では如何ともしがたい部分もありました。

開発の反省

単純なバグや限られたパワーでの開発のため諦めた対応等、うまくできなかった部分も結構ありました。(あるのかわからんが)次回以降の反省にしたい点です。

.NET Standard 2.0 対応したい

イベントアプリは UWP でも使えるので、.NET Standard 2.0 にすると Fall Creators Update より前を切り捨てることになります。それは無理だろうな、ということで今回はあきらめました。

結構動きがもっさり(特に Android

セッション数が多かったり、聴講者属性表示機能の追加等で動きが遅くなったと思います。もっと最適化できる部分があったハズ。

iPhone X レイアウト

iPhone X に画面レイアウト(Home Bar 等)を対応するため手抜きな方法をとりました。SafeArea プロパティを True にしただけ*5です。もっとちゃんと対応したかったです。

アプリアップデート強制する?

Ver.1.0.0 がゴールデンウイーク明けにリリースされ、その後、イベントの数日前にバージョンアップしたのですが、イベント当日も Ver.1.0.0 のままの方がいらっしゃっいました。アプリ内のお知らせでも周知していたのですが、結局そのままになっていたかもしれません。
旧バージョンでは特定の操作をするとアプリが落ちるバグがあり、その Crash ログも飛んできていたため、アップデートしてほしかった…(1.0.0 はスタンプラリーとか会場マップも Coming Soon だったけど…)
アプリ起動時にバージョンをチェックしてアップデートを強制にするか迷ったのですが、リリース直後に入れてイベント当日の受付直前にアプリを起動してアップデートをしなければならないとかが発生して受付が滞ってしまったり、しょうがなくモバイルネットワークでのアップデートをするしかなくなって"ギガ"が減るとかあるかもな~と思い、やりませんでした。(工数的にやれなかった側面もありますが…)
まぁ最初からバグ仕込むな、スケジュールに余裕を持ってリリースしろってことですかね。

セッション一覧自動スクロール

セッション一覧には現在時刻以降のセッションまで自動でスクロールする機能が前回まであったのに別件の対応でデグレして機能がなくなってたみたいです…。セッション数も過去最高で自分でアプリ使っていて結構不便でした。というか マイスケジュールと同じ様に開催日でタブにした方がよくないか?

最後に

ともかくなんとか終わってよかったです。
アプリ開発/リリースと自分のセッション準備、イベント問い合わせサポート等々、しばらく忙殺されていて家族にもだいぶ負担をかけたのでしばらくはおとなしくしています。
自セッションの振り返りとデモでできなかった部分などは別記事でまとめようと思います。

Visual Studio 2017 Version 15.5 にアップデートしたら Android が表示されなくなった時の対処方法

qiita.com
↑のクリスマスイブ分の穴埋めです。

やっつけですが、ご容赦を。


Visual Studio が 2017 になってからアップデートが短いサイクルで行われるようになりました。
一応、ReleaseNote はぺろーっと眺めてから(なにも考えず)実行しているのですが、問題が発生しました。
Visual Studio 2017 15.5 リリース ノート

久しぶりに Xamarin.Forms のプロジェクトを開いてみると、ツールメニューから「Android」がなくなりました。
なにを言ってるかわからないかもしれませんが、なくなりました。
f:id:ShunsukeKawai:20171226154456p:plain:w400

↓↓↓正しい姿↓↓↓
f:id:ShunsukeKawai:20171226155422p:plain:w400

Androidデバッグ実行もアーカイブもできなくなっています。

対処方法

Visual Studio Installer を起動して以下の2つを選択してからインストールを実行します。
f:id:ShunsukeKawai:20171226154805p:plain

Ver.15.5 から Android 標準の SDK Manager とは別に Xamarin 用のが追加されたようですね。
そしてそれはデフォルトではインストール対象外になっているようです。。
今回の問題自体は Android SDK セットアップ(API レベル 25)が原因らしいですが、SDK Manager も一緒に入れちゃいましょう。

【参考:Xamarin Android SDK Manager の画面】
f:id:ShunsukeKawai:20171226160607p:plain

蛇足

ちゃんと開発環境の更新をする時は変更内容を確認しましょう。(自戒)
でもアップデートが頻繁過ぎてつらいなぁ。
Xamarin も VS に含まれて更新されるから全然関係ない更新もあるし、個別に更新してた時の方が楽だったかもな。
チームメンバー内で環境を統一するのは楽になったけど、1週間に1回ぐらい更新すべきかを判断して更新するって(30分もかからないけど)タスクが増えちゃう。
みんなめんどくさくないのかなぁ?

Xamarin.Forms 製アプリを iPhone X で動かしてみた(やっべぇぞ

Visual Studio for Mac | Xamarin Releases
ここに書いてある方法で Visual Studio for MaciOS 11 を動かせるようにしました。

んで、Xamarin.Forms で簡単なアプリを実行してみました。
こんな XAML です。よくある iOS 用に画面上部の Padding に 20 設定してあるヤツです。
嫌な予感はしていました。

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="test.Views.MyPage" BackgroundColor="Teal">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="Android, WinPhone">0</On>
            <On Platform="iOS">0,20,0,0</On>
        </OnPlatform>
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Xamarin.Forms iPhone X Test" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

で実行すると…

f:id:ShunsukeKawai:20170915154301p:plain
ぐわー、やっぱりー。
いろんなアプリ見直さなきゃーー

#どうでもいいけど、シュミレーターのスクショがカメラの部分透過になるんだな

==================
20170915_追記1
NavigationPage を親にして先ほどの画面を表示するとこんな感じになります。
f:id:ShunsukeKawai:20170915202653p:plain

==================
20170915_追記2
以前作成した de:code 2017 の公式アプリを動かしてみました。意外になんとかなってる…のかな…
f:id:ShunsukeKawai:20170915211439p:plain:w200 f:id:ShunsukeKawai:20170915211447p:plain:w200 f:id:ShunsukeKawai:20170915211456p:plain:w200

Xamarin.Forms で iOS のステータスバーとナビゲーションバーの色を動的に変えたい(仮)

前回の記事ではナビゲーションバーに色付きアイコンを置けるようにしました。
shunsukekawai.hatenablog.com


ナビゲーションバー系繋がりで、ステータスバーとナビゲーションバー自体の色をページによって動的に変えたかったのでやってみました。
タイトルに(仮)が付いてるのは結構無理やりというか、もうちょいスマートなやり方ないのかなー。と思ってるからです。誰か教えてください。

完成形

f:id:ShunsukeKawai:20170907203753g:plain:w300

作成方法

PCL 側にこんなカスタムコントロールを作成します。

ナビゲーションバーの色(NavigationBarColor)とステータスバーのスタイルをデフォルトか(IsUseDefaultBarStyle)の BindableProperty を追加した ContentPage を継承したクラスです。

iOS の プロジェクトに CustomRenderer を作成します。
  • OnElementChanged で上で作成したプロパティを取得してメンバー変数に格納
  • ViewWillAppear でステータスバーの種類を設定、ナビゲーションバーがある場合は色を設定
  • 右側のアイコンボタンの種類を設定(前回の記事分のアイコンにモードを設定するヤツ)


iOS プロジェクトの info.plist に View controller-based status bar appearance というプロパティを追加し、NO を設定します。

これをしないとステータスバーのスタイルが変更できません。
f:id:ShunsukeKawai:20170907214852p:plain

各ページをカスタムコントロールにして、プロパティを設定

以下のように遷移するようになってます。今までのもひっくるめて Github にアップしておきます。
MainPage→SecondPage
      ↓
     ModalPage
github.com

Xamarin.Forms で iOS のナビゲーションバーに色付きアイコンを置きたい

Xamarin.Forms の NavigationBar のアイコンを設定したい場合、以下のように ToolbarItems を使ってアイコンを追加します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="ColorNavigationBarIcon.Views.MainPage"
             Title="MainPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Icon="Icon-Small.png"></ToolbarItem>
    </ContentPage.ToolbarItems>
  <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
    <Label Text="{Binding Title}" />
  </StackLayout>
</ContentPage>

Icon-Small.png は Xamarin.Forms のプロジェクトテンプレートからプロジェクトを作成した時に勝手に追加されるこのアイコンです。
f:id:ShunsukeKawai:20170901212120p:plain

で、このアプリを実行してみると…
f:id:ShunsukeKawai:20170901220106p:plain:w300
となります。塗り潰されとる。
Apple の高尚な思想なのかなんなのか知らないですが、デフォルト単色になっちゃうみたいです。

試しに App.xaml とかのリソースでスタイルを定義して NavigationPage のテキストに色を付けてみます。

<Application.Resources>
    <ResourceDictionary>
        <Style TargetType="NavigationPage">
            <Setter Property="BarTextColor" Value="Red" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

で、実行すると…
f:id:ShunsukeKawai:20170901220144p:plain:w300
赤くなります。どうやら BarTextColor に定義されてる色で塗り潰されるのかな。

あの六角形のアイコンが見たいです。

まずは Xamarin に関係なくネイティブでのやり方を調べてみます。
参考:[Swift]UIImageのレンダリングモードまとめ - Qiita
ほうほう、UIImageRenderingMode とかいうヤツがなんかしてるんだな。

ということで、iOS のプロジェクトに Rendererを追加します。
色々やった結果、以下でなんとかなりました。

using ColorNavigationBarIcon.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ContentPage), typeof(ColorIconContentPageRenderer))]
namespace ColorNavigationBarIcon.iOS.Renderers
{
    public class ColorIconContentPageRenderer : PageRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            if (this.NavigationController == null) return;

            var items = this.NavigationController.TopViewController.NavigationItem;

            foreach (var item in items.RightBarButtonItems)
            {
                if (item.Image == null) continue;

                item.Image = item.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
            }
        }
    }
}

じゃーん
f:id:ShunsukeKawai:20170901220157p:plain:w300
わーい

de:code 2017(Day 1 / Day 2)が終わって

●本記事はポエムです。

2017/5/23-24 に開催された de:code 2017 の公式アプリを Xamarin.Forms で開発しました。

イベントアプリ自体は 2016/9 の Microsoft Foresight、2016/11 の Microsoft Tech Summit に続き3回目なのですが、de:code はデベロッパー向けのイベントのため今までとは反応が違うんだろうなぁ、と開催前から思っていました。
イベント自体の来場者数は Tech Summit と大差ないのにアプリのインストール数もざっくり3倍ぐらいです。
予想通りアプリ公開直後から様々なご意見が散見されて中には手厳しいものもあり、 Twitter を見るのが怖くなったり、イベントが継続不可能になるほど炎上している夢を見たり、自分のセッションの準備もあるわでだいぶてんやわんやでした。。

結果として正直、反省点だらけです。

スタンプラリー

今回新たに追加したスタンプラリー機能ですが、メッセージが適切でなかったり(iOS では位置情報の許可も必要なのに Bluetooth が無効と延々表示される)、スタンプが取得できないと問い合わせをいただいたりもしました。
これは確認漏れや、端末の個体差、会場の電波状況等々、こちらの考慮不足です。おそらく全員が問題なく使用できるようにするというより、Beacon を使用したスタンプの取得ができない方の救済措置があった方がよかったと思いました。QR コードや最悪、紙での代替などを用意しておけばよかったです。
元々、ブース出展社の方のお手を煩わせないように、という目論見もあり Beacon のみで行うことになったのですが、逆に問い合わせ対応が増えてしまったようです。
うまくできなかった方、問い合わせ対応で時間が取られた出展社の方にはご迷惑をおかけしました。申し訳ありません。

その他問題

アプリのリリース時期も色々あって、イベントの数日前になってしまいフィードバックを反映する時間もなく、ぶっつけ本番的な感じになってしまいました。
また、サーバー側の DB/API はウチの担当ではなかったですが、パスワードに記号が入ってるとログインできない(ログイン API 関連)、QR コードが出てこない(参加情報取得 API で正しい値が取得できない)、アンケートが出てこない(イベント受付時のデータ登録がうまくできてない)等々、アプリ外の問題も発生していて想定が甘かった箇所もありました。

Xamarin.Forms での開発

開発に関しては、まぁこれでいーんじゃない?とりあえず作りあげよう精神で突き進んで来ました。
今回は細かい部分の調整をする余裕があまりなかったため、利用者の方々にはご不満やご不便をおかけすることもあったかと思います。
「逆に Microsoft の技術のネガキャンになっちゃうんじゃない?」的なご意見も見かけました。
個人的には、Xamarin.Forms で全プラットフォームに対してベストなアプリを作るのは潤沢な工数、期間がないと難しく、Xamarin.Forms はそれなりの工数でそれなりのアプリを作れる(素晴らしい)開発環境だと思っています。(というか潤沢にあってベストまたはそれに近い UI を実現するのであれば Forms 使わない方がいいと思ってる。もちろんプラットフォームの理解も必要だけど。)
==================

  • ちょっと誤解を招きそうなので追記

当然ながら今回のアプリが Xamarin.Forms の限界なわけではありません。
色々妥協はしていますし、私たちがいたらない箇所も多々あったと思います。
==================

メモ:次回まで改善したい(とりあえず思いつくまま)

全体

  • ログインしなくても使える機能は開放する
  • セッション編集画面の自動スクロールの時間が Hour でやっているため次の次の時間帯にスクロールしてしまう可能性がある
  • フィルターの全クリア処理追加
  • 問い合わせ先を明記する
  • パスワード忘れのリンクをログイン画面に置く
  • ログイン時エラーの場合は中途半端なデータを作らない
  • マップ画像キャッシュ系(更新された時のためにキャッシュを無効にしているが、オフラインだと取得できない)
  • UI 全体的に見直し
  • スタンプラリーができない場合の救済措置(QR コードなど)
  • 空席状況をもっと厳密に出したかった
  • アプリ更新があった際のストアへの誘導

iOS

  • ステータスバーの色
  • Bluetooth と位置情報が必要なのに Bluetooth のメッセージしかでない
  • スクロールのパフォーマンス

Android

  • ドロップダウンのデザイン
  • ログイン画面のテキストの配色
  • 画像ピンチインやりにくい
  • 戻るでアプリ終了しない、もしくは再開時に復帰する
  • Push 通知が折り返さない、展開できない

UWP

  • 画像ピンチインできない
  • 早くスクロールすると黒くなる

さいごに

反省点も多々ありますが、なんとか終わり、ポジティブな感想をいただくとやっぱりうれしかったです。
そういったご意見にだいぶ救われました。
また、ウチはアプリ開発を担当しただけでイベント運営ではないですが、運営側に勝手に口出しして色々中の様子を見ることができ、とても勉強になりました。
運営の方々はほんとに大変そうで、来場者の方をどう満足させるかに全力を注いでいて、どんなイベント、サービスもたくさんの人々の努力によって形成されてることを改めて認識しました。
自分がユーザーの立場になった際にはいいと思った点もちゃんとフィードバックしようと深く心に刻みました。
(去年の de:code は参加者側で文句言いまくってた)