Microsoft 系のあれこれ

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

Microsoft365グループから作成したTeamのチャネル内会議を予定するとメンバー全員の予定に入ってしまうのを回避する

Teamsのチャネル内で会議を開催すると会議でのチャットの履歴がチャネルに残るので会議に参加してないメンバーにも情報連携できたり、情報が分散してしまう(野良会議だとチャットのカテゴリーにしか残らない)のを防げるので基本的に普段の業務で会議を開催する場合は活用しています。
会議の作成画面にチャネルを追加すれば大丈夫です。
f:id:ShunsukeKawai:20210603112551p:plain
非常に便利な機能ですが、Microsoft 365グループが絡むとある問題が発生しました。

AzureADの動的グループ

本記事の前提として、社内ではAzureADの動的グループというのを活用して365グループを作成し、そのグループをもとにTeamsチームを作成しているのがいくつかあります。
動的グループとはAzureADの属性に対して条件を指定するルールを作成し、そのルールに合致するメンバーを自動で管理してくれる仕組みです。
動的に設定されるグループ メンバーシップのルール - Azure AD | Microsoft Docs
指定したクエリに該当するメンバーを自動的にグループに追加・削除され、メンバーのメンテナンスが必要ないので非常に便利です。
これらはウチの会社では組織全員(組織全体でチーム作成が諸事情により使えないケースがあった)、プロパー社員全員など、総じて大人数のグループで運用しています。

チャネル内会議の予定がメンバー全員の予定表に登録されてしまう

さて本題の問題です。
動的グループだけでなく、Microsoft 365グループから作成されたTeamsチームのチャネル内会議を予定すると、そのグループに所属するメンバー全員の予定表に登録されてしまいます。 会議自体は少人数で行いたくても全員(ウチの場合だと数百人)の予定表に登録されるのでいい迷惑ですね。
逆に全員の予定に入れたい会議などがある場合は便利なのかもしれませんが、今回はそうではありません。

問題が発生する原因

本問題は下記のグループに対しての各人の設定によりチャネル内会議の予定表追加するかが決まります。
f:id:ShunsukeKawai:20210603165121p:plain
※ ちなみにこの設定はOutlookのWeb版でしか確認する術がわかりませんでした。
この「受信トレイでのフォローを停止する」の設定が「自分への返信だけを受信する」になっている場合は、チャネルで会議が予定されても参加者と指定されているメンバー以外の予定表には入りません。
そして「自分への返信とグループのイベントだけを受信する」になっている場合は、チャネルで会議が予定されると参加者でなくとも予定表に追加されてしまいます。
そのため、迂闊にチャネル内の会議が開催できません。

厄介ポイント①

Teamsから新規に作ったチームのグループ(チームを作ると自動的にグループも作成される)では規定値が「自分への返信だけを受信する」になっていて、365グループを作った際の規定値は「自分への返信とグループのイベントだけを受信する」になっています。
と、設定がそれぞれのルートで異なり、ユーザーはどちらのルートで作成されたチームなのか普通は知らないので使い分けができません。

厄介ポイント②

この設定は個人の設定であるため、管理者が後から強制的に変更することは基本的にできない。
(基本的にとついている理由の説明は後述します)

問題の回避策

後から各人の本設定を変更することはできませんが、新しくグループにメンバーを追加した際に「自分への返信だけを受信する」に設定されるような指定ができます。

設定方法

PowerShellの管理モジュールで365グループの AlwaysSubscribeMembersToCalendarEvents 設定をfalseに変更してあげます。

AlwaysSubscribeMembersToCalendarEventsの公式説明

具体的な設定方法は下記の通りです。
作業はPowerShell ISEでやりました。(F8で行実行できるから試しながらやるの便利)

Import-Module ExchangeOnlineManagement

でモジュールをインポートして

Connect-ExchangeOnline -UserPrincipalName XXXXXXX@XXXXX.com

を実行するとサインイン画面が表示されるのでサインインしExchangeに接続します。

  • 該当グループの設定情報を確認
    以下のコマンドレットで現在のグループの設定方法を確認します。
    TestGroupの部分は該当のグループのメールアドレスの@以前を指定するとひっかかると思います。
Get-UnifiedGroup -Identity "TestGroup" | Select DisplayName,AlwaysSubscribeMembersToCalendarEvents

実行結果は以下の通りTrueになってます。
f:id:ShunsukeKawai:20210603183458p:plain

  • AlwaysSubscribeMembersToCalendarEventsの設定を変更する
    以下のコマンドレットで設定をFalseに設定してあげます。
Set-UnifiedGroup -Identity "TestGroup" -AlwaysSubscribeMembersToCalendarEvents:$False

完了後、もう一度確認するとFalseに変更されています。 f:id:ShunsukeKawai:20210603183732p:plain

ですが、本設定はグループに新規追加されたメンバーに対して設定がされるため、既存メンバーの設定には反映されません。

設定完了後、メンバーを削除して再追加する

設定が完了したグループにメンバーを追加してあげると「自分への返信だけを受信する」になっていることが確認できました。
そのため、動的グループを利用して365グループを作成している場合は一度ルールを誰も当てはまらないように変更して、それが反映されメンバーがいなくなった後にもう一度ルールを指定することで新規追加扱いになり、全員の設定を実質変更したことになります。
通常の365グループの場合はメンバーを事前にエクスポートしておいて、削除後、再度インポートすればいいでしょう。
再度各メンバーに「グループに追加されました」的な通知が行ってしまうのは我慢するしかない…

おまけ

この設定をした後でもメンバー全員に(強制的に)会議の予定を追加したい場合はグループの編集画面から下記設定をONにするとできるみたいです。
f:id:ShunsukeKawai:20210603184558p:plain

まとめ

なんとかやりたいことの実現ができましたが、規定値が違うのはどうにかしてほしい…
かといっていつの間にかどっちかに統一されたら困るけど…(特に「自分への返信とグループのイベントだけを受信する」に統一されたら阿鼻叫喚が容易に予想できる)

Teamsのメッセージ内容ごとコピーして他のアプリに貼り付ける便利な方法

※ 本記事の方法は Windows の Teams デスクトップアプリでしか確認してません。

Teams でメッセージのリンクをコピーする時どうしてますか?
たぶん、メニューから「リンクをコピー」ってしてる方が多い気がします。
f:id:ShunsukeKawai:20210512121035p:plain

そうするとそのコピーした内容を Teams に貼り付けるとこうなります。
f:id:ShunsukeKawai:20210512121033p:plain
何時何分に誰がどこのチャネルに投降した内容かをわかるので Teams 内だけでやり取りする分にはいいかもしれません。

では、他のアプリとかに貼り付ける場合はどうでしょう?
今回の例では GitHub の Issue にこのメッセージの問題だよーって貼り付けるケースをイメージしてください。
f:id:ShunsukeKawai:20210512121030p:plain

はい、当然ながら URL しか貼り付けられません。
これだとリンクに飛ばないとどんな内容かわかりませんね。

Teams のメッセージを他のアプリにコピペする時に便利な方法

ということで本題です。
といっても難しいことはなくて投稿者の名前と日時の部分をマウスで選択してあげて Ctrl + c でコピーするだけです。
f:id:ShunsukeKawai:20210512121041g:plain

これをするとなぜかメッセージ全体が選択されます。
画像の通り、詳細表示がある長いメッセージでも全部選択されます。

では、これをコピーして同じように GitHub の Issue に貼り付けてみましょう。
f:id:ShunsukeKawai:20210512121038p:plain

変な改行は入りますが、投稿者、日時(当日だと時間だけしか入らない)、メッセージ内容、おまけにメッセージへのリンクまでついてくるサービス精神。最高です。
これで他のアプリなどにメッセージをそのまま貼り付けることができます。
いちいちリンクに飛ばなくても内容を確認できるので便利ですね。

Teams のアップデートにより、いつこの方法が使えなくなるかわかりませんがそれまではよかったら使ってみてください。

PowerAutomateでSharePointのリストアイテム取得時にユーザー列のメールアドレスで絞り込む

「複数項目の取得」の条件にユーザー列を使いたかったので調べてみました。
フィルタークエリの公式ドキュメントはこちらです
https://docs.microsoft.com/ja-jp/sharepoint/dev/business-apps/power-automate/guidance/working-with-get-items-and-get-files#filter-queries

んで色々調べた結果、以下で取得できました。

Employee/EMail eq 'Shunsuke_Kawai@xxxx.com'

Employee(表示名でなく論理名)というユーザー列のEmailを指定していますが、この指定が「Email」でも「email」でもなく「EMail」じゃないと失敗するのが厄介でした。

↓こんな感じ
f:id:ShunsukeKawai:20210225131253p:plain

PowerAutomateで明日の10時までの分数を取得する

Teamsにリマインダー機能を追加したかったので標準にあるテンプレートをちょっとカスタムして明日の10時に通知する選択肢を追加しました。
Follow up on a message | Microsoft Power Automate

この仕組みは時間指定じゃなくてどれだけ待機するかを指定するので、明日の10時までの分数を算出しないといけません。
それが結構めんどくさかったのでメモメモ。
もっとうまいやり方あるのだろうか。。。

div(sub(ticks(addHours(startOfDay(addDays(convertFromUtc(utcNow(), 'Tokyo Standard Time'), 1)),10)), ticks(convertFromUtc(utcNow(), 'Tokyo Standard Time'))), 600000000)

一行で解説したかったので現在時刻取得を2回書いてますが、変数とかにした方がいいですね。

文で書くのめんどくさかったので解説は画像で。
f:id:ShunsukeKawai:20201030170044p:plain

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

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

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

※※※2020/09/14 追記※※※※※※※※※※※※
イコン画像によってエラーになってうまくいかない場合がありました。
>HTTP 要求に失敗しました。コンテンツが有効な JSON ではありませんでした。

あくまで予想なのですが、バイナリが大きすぎるとエラーになるっぽい挙動をみせています。
そのため、一回OneDriveとかにアップしてその画像を取得/表示するか、以下のようにエラーが発生したら諦めて画像なしで投稿するようにしましょう。
・Teams投稿のアクションをコピーして、すぐ下に貼り付け
・投稿のJSONから画像の部分を削除
・貼り付けたアクションの実行条件の構成を前のタスクに失敗した場合を追加
f:id:ShunsukeKawai:20200914185054p:plain
f:id:ShunsukeKawai:20200914185023p:plain
※※※※※※※※※※※※※※※※※※※※※※


  • 投稿内容と自動付加される境界に線を引く

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

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

線がないのとあるのじゃなんとなく印象が変わる気がしますよね。
変わんないじゃんと思っていても言わないでください。
f:id:ShunsukeKawai:20200914184522p: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分もかからないけど)タスクが増えちゃう。
みんなめんどくさくないのかなぁ?