kenichiro246’s blog

主にC#での仕事をしてます。今はAWSに関わり始めました。

Windows11 WSL2+Debian docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. の解決方法

事象

docker docs の手順に沿ってインストールしてたら、件名のエラーが発生したので、その解決方法となります。

matsuand.github.io

エラーメッセージはこんな感じ

$ sudo service docker start
grep: /etc/fstab: No such file or directory
Starting Docker: docker.

$ sudo docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.

環境

name ver
OS Windows 11 Pro (21H2)
Debian 11.3
docker-ce 20.10.17, build 100c701

解決方法

結論から言えば、私の環境では以下を実行すると解決した。

$ sudo touch /etc/fstab
$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
$ sudo service docker start

※参考:WSL2 の debian で docker サービスが起動しない

なぜ?

$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).

  Selection    Path                       Priority   Status
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        auto mode
  1            /usr/sbin/iptables-legacy   10        manual mode
  2            /usr/sbin/iptables-nft      20        manual mode

Press <enter> to keep the current choice[*], or type selection number:

$ ls -l /usr/sbin/iptables
lrwxrwxrwx 1 root root 26 Jun 12 01:02 /usr/sbin/iptables -> /etc/alternatives/iptables
$ ls -l /etc/alternatives/iptables
lrwxrwxrwx 1 root root 22 Jun 12 01:02 /etc/alternatives/iptables -> /usr/sbin/iptables-nft
  • Dockerはiptablesを推奨?
    参考)Docker and iptables

  • iptables-nftで定義を設定すると,iptables-legacyの定義は無視(?)され、外部との通信ができない。そのため、iptables-legacyをデフォルトに変更し,定義をlegacy側に寄せて対処する。

※参考)Debian 10(buster) + ufw + Docker: Dockerコンテナが外部と通信できない問題の対処

手順

解決方法のところで書いた内容の詳細です。(備忘のため)

$ sudo service docker start
grep: /etc/fstab: No such file or directory
Starting Docker: docker.

$ sudo docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.

$ sudo touch /etc/fstab

$ sudo service docker start
Starting Docker: docker.

$ sudo docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.


$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).

  Selection    Path                       Priority   Status
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        auto mode
  1            /usr/sbin/iptables-legacy   10        manual mode
  2            /usr/sbin/iptables-nft      20        manual mode

Press <enter> to keep the current choice[*], or type selection number:

$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives: using /usr/sbin/iptables-legacy to provide /usr/sbin/iptables (iptables) in manual mode

$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives: using /usr/sbin/ip6tables-legacy to provide /usr/sbin/ip6tables (ip6tables) in manual mode

$ sudo docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.

$ sudo service docker start
Starting Docker: docker.

$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).

  Selection    Path                       Priority   Status
------------------------------------------------------------
  0            /usr/sbin/iptables-nft      20        auto mode
* 1            /usr/sbin/iptables-legacy   10        manual mode
  2            /usr/sbin/iptables-nft      20        manual mode

Press <enter> to keep the current choice[*], or type selection number:

$ sudo docker run hello-world
:
Hello from Docker!
This message shows that your installation appears to be working correctly.
:

まぁ、慣れてない者には難しい話です・・・。

Lambda関数からLayerのコードを呼び出す方法(ZIPファイルアーカイブ版)

概要

ZIP化したPythonのコードをLayerへデプロイし、別のLambda関数から呼び出します。
必要最小限の構成で作れるようにしており、WindowsPowerShell を使い、AWS CLI で構築できる手順としています。
また、AWSでは、Lambda関数のコードは「コンテナイメージ」と「ZIPファイルアーカイブ」の2種類のデプロイパッケージをサポートしており、今回は「ZIPファイルアーカイブ」で構築します。

前提条件

  • AWS CLI がインストールされている。
  • 今回は Windows で構築します。

デプロイパッケージの構成

最終的にはこんなイメージの構成となります。

/test1Lambda
 ├ lambda_function.py
 └ Layer
   └ test1Layer(test1_function.py)

全体の流れ

以下の流れで作業を進めます。

  1. PythonでLambda関数を作成する
  2. ZIPファイルアーカイブを作成する
  3. Layerにデプロイする
  4. Layerを呼び出すLambda関数を作成する
  5. Lambda関数を実行する

PythonでLambda関数を作成する

以下のとおりLambda関数のファイルを作成します。 この時、フォルダは「python」にする必要があります。
もしフォルダ名を変えてしまうと、このLambda関数が参照できない状態になります。
※安易にフォルダ名を変更してしまい、Lambda関数が参照できない事象が発生し、解決するまで地味にハマりました。
参考:https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-import-module-error-python/

> 重要:Python 用にインポートするライブラリを /python フォルダ内に配置します。
mkdir python
New-Item -ItemType file python/test1_function.py
Invoke-Item python/test1_function.py

test1_function.py

def func1():
    return 'Hello test1_function.func1 !!'

ZIPファイルアーカイブを作成する

PowerShell で以下を実行して、ZIPファイルアーカイブを作成します。
ZIPファイルの中身は、「python」フォルダとその配下に「test1_function.py」が含まれていればOKとなります。

Compress-Archive -Path python/ -DestinationPath test1-package.zip

Layerにデプロイする

  • S3 へアップロードする
    ※S3のバケット名は全世界で一意にする必要がありますので、適宜変更してください。
aws s3 mb s3://test1-bucket
aws s3 cp test1-package.zip s3://test1-bucket/ --acl public-read
  • S3 から Lambda のレイヤーへデプロイする。
aws lambda publish-layer-version --layer-name test1Layer --description "test1 Lambda" --license-info "MIT" --content S3Bucket=test1-bucket,S3Key=test1-package.zip --compatible-runtimes python3.9 --compatible-architectures "x86_64"

Layerを呼び出すLambda関数を作成する

  • 以下の内容でLambda関数を新規作成する

    プロパティ
    関数名 test1Lambda
    ランタイム Python 3.9
    アーキテクチャ x86_64
    実行ロール 基本的な Lambda アクセス権限で新しいロールを作成
  • 作成した関数の「Layer」セクションで、「レイヤーの追加」をクリックする。

  • 「レイヤーを選択」セクションで「カスタムレイヤー」を選択し、ZIPファイルアーカイブのLambda関数を選択する。この時、バージョンも指定する。

  • 「追加」をクリックする

Lambda関数を実行する

  • Lambda関数「test1Lambda」の lambda_function.py を以下のとおり変更する。
import test1_function

def lambda_handler(event, context):
    return test1_function.func1()
  • デプロイ後、「Test」をクリックして以下のとおり表示されれば成功です!
 Response
 "Hello test1_function.func1 !!"

こんな感じで簡単にできますね。

Swagger で AWS の API Gateway を初めて構築してみた

タイトルのとおり構築していきます。
yamlファイルの内容は掘り下げず、まずは API Gateway が作れるところまでとします。

事前準備

まずは Swagger を使うために、VS Code で「Swagger Viewer」をインストールしておきます。

参考

Swagger Spec ファイルの作成

  1. yaml ファイルの作成
    以下の内容が記述された yaml ファイルを作成します。
    バックエンドで PetStore ウェブサイトの HTTP エンドポイントと統合された GET / メソッドのみを公開し、200 OK レスポンスを返すという仕様です。
    AWSには PetStore ウェブサイトというAPIを提供している架空のサイトがありますので、これを使います。
{
  "swagger": "2.0",
  "info": {
    "title": "Simple PetStore (OpenAPI)"
  },
  "schemes": [
    "https"
  ],
  "paths": {
    "/pets": {
      "get": {
        "responses": {
          "200": {
            "description": "200 response"
          }
        },
        "x-amazon-apigateway-integration": {
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "http"
        }
      }
    },
    "/pets/{petId}": {
      "get": {
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response"
          }
        },
        "x-amazon-apigateway-integration": {
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.path.id": "method.request.path.petId"
          },
          "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "http"
        }
      }
    }
  }
}
  1. VS Code で「Shift + Alt + p」を押して Swagger Viewer を開く
    こんな感じでAPIの定義が見れます。

API Gateway の作成

  1. API Gateway コンソールを開く
  2. API を作成」をクリックする
  3. REST API セクションの「インポート」をクリックする
  4. 以下のとおり入力し、「インポート」をクリックする
項目
プロトコルを選択する REST
新しい API の作成 Swagger あるいは Open API 3 からインポート
Swagger あるいは Open API 3 からインポート 前述に記述した Swagger Spec ファイルを選択
エンドポイントタイプ リージョン

API Gateway の検証

Swaggerで作成した API Gateway をデプロイし、「URL の呼び出し」から以下の全量検索やID検索のように表示されれば成功です。

全量検索

  1. ブラウザで以下のURLを開く
    http://petstore-demo-endpoint.execute-api.com/petstore/pets
  2. 以下の内容が表示されたらOK
[
  {
    "id": 1,
    "type": "dog",
    "price": 249.99
  },
  {
    "id": 2,
    "type": "cat",
    "price": 124.99
  },
  {
    "id": 3,
    "type": "fish",
    "price": 0.99
  }
]

IDでの検索

  1. ブラウザで以下のURLを開く
    http://petstore-demo-endpoint.execute-api.com/petstore/pets/2
  2. 以下の内容が表示されたらOK
{
  "id": 2,
  "type": "cat",
  "price": 124.99
}

yaml ファイルさえあれば、API Gateway にインポートするだけで作成できちゃいますね。簡単。

AWS CloudFormation を初めて使ってみた

AWS CloudFormation

仕事で CloudFormation を使うことになりそうなので、まずは簡単なところから。
CloudFormation を使って、AWS の超最小限の構成を自動で構築してみます。 細かな設定まわりは次回書いてみようかな。

テンプレートファイルの作成

  1. YAML または JSON 形式の CloudFormation テンプレートを作成します。
    ファイル名は何でも良いです。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  TestVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources": {
        "TestVpc": {
            "Type": "AWS::EC2::VPC",
            "Properties": {
                "CidrBlock": "10.0.0.0/16"
            }
        }
    }
}

CloudFormation スタックの作成

  1. Webコンソール
    CloudFormationのWebコンソールを開きます。
  2. テンプレートファイルのアップロード
    「CloudFormation スタックの作成」から「スタックの作成」ボタンをクリックします。

    項目
    前提条件 - テンプレートの準備 テンプレートの準備
    テンプレートの指定 テンプレートファイルのアップロード
  3. デザイナー表示
    「デザイナーで表示」ボタンをクリックするとアップロードしたテンプレートのアーキテクチャが表示されます。 f:id:kenichiro246:20220409010058p:plain

  4. テンプレートの検証
    デザイナーの画面で「テンプレートの検証」ボタンをクリックすると、その名のとおりテンプレートを検証してくれます。試しに、AWSTemplateFormatVersion の値を適当な値に変更し、「テンプレートの検証」ボタンをクリックするとエラーになります。
    ※2022年4月時点では、この AWSTemplateFormatVersion の値は「2010-09-09」と指定する必要があります。 f:id:kenichiro246:20220409010215p:plain

  5. スタックの作成
    「スタックの作成」ボタンをクリックし、「次へ」ボタンをクリックする。

  6. スタックの詳細を指定
    以下のとおり入力して、「次へ」ボタンをクリックする。

    項目
    スタックの名前 TestStack1
    パラメータ なし(特に入力する項目はない状態)
  7. スタックオプションの設定
    特に変更せず、「次へ」ボタンをクリックする。

  8. レビュー
    特に変更せず、「スタックの作成」ボタンをクリックする。
  9. スタックのダッシュボード
    ステータスが「CREATE_IN_PROGRESS」となり、その後「CREATE_COMPLETE」となれば作成完了となります。 f:id:kenichiro246:20220409010241p:plain

  10. VPCダッシュボード
    VPCダッシュボードを開くと、今作成したスタックが作成されています。作成したスタックの VPC の Name は未設定なので、この時点で VPC を大量に作成している場合は見つかりづらいですが、タグを見てみると「aws:cloudformation:stack-name | TestStack1」となっているため、このあたりで作成できたことが確認できます。 f:id:kenichiro246:20220409010253p:plain

CloudFormation スタックの削除

  1. CloudFormation のスタックの一覧で、削除したいスタックを選択する。
  2. 「削除」ボタンをクリックする。

こんな感じで、簡単にできちゃいますね。

AZ-900: Microsoft Azure Fundamentals 合格記録(2020年7月)

訳あって Azure を学ぶ必要があり、独学で勉強しつつ、資格を取ってみることにしたので、その結果を公開しようと思います。
AZ-900 を受けるにあたり、何を勉強したらいいのかを抑えたい人は参考になるかもしれません。

スペック

以下のとおりです。Azure 全然わからんからスタートしています。

  • SE 10年+α
  • 現在はシステムの維持・保守がメイン
  • Azure 全然関わってない
  • IaaS は独学で チョットワカル レベルくらい

AZ-900: Microsoft Azure Fundamentals とは

公式は以下のとおり記載されています。
要は Azure とは何ぞや?に対して回答できるレベルの証明という感じですかね。

Azure Fundamentals 認定資格の受験者は、クラウド サービスの基礎知識と、それらのサービスが Microsoft Azure でどのように提供されるかについての知識が必要です。
Azure Fundamentals 認定資格は、クラウドの概念、Azure のコア サービス、Azure の価格、SLA、ライフサイクル、およびクラウドのセキュリティ、プライバシー、コンプライアンス、信頼の基礎に関する知識を証明する機会です。
この認定資格は、クラウドベースのソリューションとサービスを使い始めた人を対象としています。
受験者は、Azure のサービス、ワークロード、セキュリティ、プライバシー、価格、サポートだけでなく、クラウドの概念に関する基本的な知識を実証できる必要があります。
また、ネットワーキング、ストレージ、コンピューティング、アプリケーション サポート、およびアプリケーション開発の概念についても理解している必要があります。

また、公式に記載されているとおり 2020/5/28 に試験の内容が更新されました。
今後も頻繁に更新される可能性は高いため、認定資格のサイトを随時チェックしておくのが良いかと思います。

受験結果

結果は以下のとおりです。見事に1回落ちました。
1000点満点中 700点以上が合格とのこと。
1問あたりの配点はわからないようになっていますが、1回目はあと2問くらい正解していれば合格していたのではないかと推測しています。

  • 2020/7/3 1回目 651点 不合格
  • 2020/7/13 2回目 820点 合格

試験の形式

選択式・ドラッグアンドドロップなど様々な形式が出てきます。
このあたりを読んでおくのが良いかと思います。
試験の内容は、秘密保持契約(NDA)があるので詳しくは書けない感じです。
https://docs.microsoft.com/ja-jp/learn/certifications/certification-exams

受験方法

自宅でも受験が可能なので、最近のコロナ事情を考えると自宅がベストなのですが、如何せん生後3ヶ月の子供がいるので、集中しやすくするためにも、人がいなさそうな平日の遅い時間にピアソンVUEで受験しました。
まぁ、自転車で行ける距離ということも選んだ理由ですが。

やったこと

Udemy

資格を取る目標を立てる前に Udemy の以下の講座を進めていました。
AZ-900 を受験するのに必須とは言いませんが、予め講座を見ておいたことで、このあと紹介する書籍の内容が理解しやすかったです。
また、この講座自体は、丁寧に細かい部分まで説明されている内容になっているため、見ておいて損はありません。

www.udemy.com

書籍「合格対策Microsoft認定AZ-900:Microsoft Azure Fundamentalsテキスト&問題集」

以下の書籍を購入し、勉強しました。
Azure 何もわからん勢なので、一通り読み込み、各章の問題集および巻末の模擬試験を徹底して解きました。
単語の意味や似たような単語の違いなど、徹底的に整理し、理解したことが合格に繋がったと思います。
2回目の受験直前は、全ての問題はほぼ完ぺきに回答できるくらいにしました。

amzn.to

Microsoft Learn

Microsoft には 「Microsoft Learn」という様々な技術などを学べるラーニング パスがあり、その中で AZ-900 に特化したいくつかのラーニング パスを見て、学習を進めました。
各ラーニング パスの最後には問題が出てくるのですが、全て解くようにしました。
こちらも、各問題は全て完ぺきに回答できるくらいにしました。

docs.microsoft.com

書籍「速習Azure Administrator」

この書籍は、前述の書籍より少し踏み込んだ内容が書かれているため、かなり参考になります。
私の場合は、合格後に購入したので、先に購入しておけば良かったと思ったほどです。
(買っておけば1回で合格できたかもしれません・・・)

Azure Portal の操作方法などの図もたくさんあるため、書籍の内容を参考に、自分で Azure Portal を操作しながら学べば、かなり身につくと思います。

amzn.to

Microsoft Learn の学習用環境(サンドボックス

合格してから知ったのですが、Azure では学習用環境として、Sandbox(サンドボックス)というものがあります。
これは、一部制限はあるものの、無課金で Azure Portal から様々な操作が可能であり、一定期間経過するとリソースにアクセス出来なくなるようです。
そのため、もしいろいろと試したいことがあれば、Sandbox を活用するのが良いかと思います。

Sandbox は以下のページから作成&ログインが出来たりします。
使い方は、かずきさんのブログがわかりやすかったです。

演習 - Azure portal を使用して VM を作成する - Learn | Microsoft Docs

blog.okazuki.jp

所感

試験の制限時間は90分(実際に問題を解くのは60分)ですが、1回目も2回目も約40分で終わりました。
試験を終了すると、すぐに合否が画面に表示される仕組みです。
試験を終えるボタンを押す時はドキドキするもんですね。
また、前述のとおりNDAがあるため、試験の内容は記載できませんが、各単語の意味や違い、特徴を抑えておけば、解ける問題ばかりだと思います。

その他

connpass を活用する

connpass では、Microsoft が度々「Azure クラウド基礎講座」を開いています。
特に AZ-900受験バウチャー付き で開催しているので、活用できるタイミングがあれば、活用したほうが良いです。
私はちょうどコロナの影響で、講座が開催されなくなってしまったので、活用は出来ませんでしたが・・・。
ちょいちょい connpass を見ておくのをオススメします。

connpass.com

有料の勉強会

「短期集中&効率よくムダなく学習」を目指すのであれば、有料の勉強会に参加はありだと思いますが、個人的には Microsoft Learn と 書籍 のみで受かることが出来ると思うので、そのあたりは自身のお財布との相談で良いかと思っています。

最後に

現在、AZ-900 を取ろうと頑張っている方、もしくは頑張ろうとしている方のお役に立てればと思っています。
皆様、頑張ってくださいね。

ちなみに私は、AZ-104:Azure Administrator Associate を目指して勉強中です。
先は長そうだ・・・。

[Xamarin]PCLを含めたTemplateの作り方

概要

タイトルのとおりVisual Studioで作成したソリューションを元にテンプレートを作成する方法です。
携わっているシステムの環境に合わせたテンプレートをさらっと作ることができれば、その環境に合わせてちょっと試したいことをすぐに試せるので便利ですよね。

当エントリーではXamarin.Formsを用いたソリューションをテンプレート化して利用できるようにしますが、最低限の作り方しかまとめていません。
そのため、完璧なテンプレートを利用したい場合は、@ytabuchi さんの Visual Studio 2017 用の PCL を使った Xamarin.Forms プロジェクトテンプレートを作りました をご利用ください。

ゴール

以下のスクリーンショットのとおり、自分で作成したテンプレートを表示させ、このテンプレートを用いてソリューションを作成後、エミュレーターで実行できるところまでをゴールとします。 f:id:kenichiro246:20180615140036p:plain

テンプレートの仕様

今回はVisual Studio Community 2017で以下のソリューションを作成し、テンプレートを作っていきます。

  • Xamarin.Forms 2.5.1
  • .NET Standard 2.0

参考

サンプル

GitHubにサンプルを置いておきます。

  • src : テンプレートの元となっているソリューション
  • template : 当エントリーに沿って作成したテンプレート

作成方法

ここからテンプレートを作成していく手順となります。

各プロジェクトファイルのテンプレート作成

テンプレート化したいソリューションを作成した後、ツールバー>プロジェクト(P)>テンプレートのエクスポート(E) をクリックし、テンプレートのエクスポートウィザードを表示させます。

ウィザード画面では「プロジェクト テンプレート(R)」を選択したままにし、「テンプレートの作成元のプロジェクトを指定してください(W)」でAndroidを選択してください。(実際にはiOSでもPCLでもOK)
f:id:kenichiro246:20180615143158p:plain

「次へ(N)」をクリックすると、オプションの選択画面が表示されますが、「テンプレートを自動的にVisual Studio にインポート(A)」のチェックを外し、完了ボタンをクリックします。

完了ボタンをクリックすると、エクスプローラーが開くのでプロジェクトのZIPファイルを解凍しましょう。
また、同じようにウィザードでiOSとPCLのプロジェクトも作っていきます。 最終的には以下のようにZIPとフォルダがそれぞれ出来上がります。 f:id:kenichiro246:20180615145324p:plain

VSTemplateの作成

エクスポート先のフォルダ(ここでは「My Exported Templates」フォルダ)にテキストファイルを作成後、MyTemplate.vstemplateへリネームし、以下の内容を書き込みます。

<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="ProjectGroup">
  <TemplateData>
    <Name>My Xamarin.Forms Template</Name>
    <Description>My Xamarin.Forms Template</Description>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType>
    </ProjectSubType>
    <SortOrder>1000</SortOrder>
    <CreateNewFolder>true</CreateNewFolder>
    <DefaultName>App</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <LocationField>Enabled</LocationField>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <CreateInPlace>true</CreateInPlace>
    <Icon>__TemplateIcon.ico</Icon>
    <PreviewImage></PreviewImage> 
  </TemplateData>
  <TemplateContent>
    <ProjectCollection>
        <ProjectTemplateLink ProjectName="$safeprojectname$">MyXamarinFormsTemplate\MyTemplate.vstemplate</ProjectTemplateLink>
        <ProjectTemplateLink ProjectName="$safeprojectname$.Android" CopyParameters="true">MyXamarinFormsTemplate.Android\MyTemplate.vstemplate</ProjectTemplateLink>
        <ProjectTemplateLink ProjectName="$safeprojectname$.iOS" CopyParameters="true">MyXamarinFormsTemplate.iOS\MyTemplate.vstemplate</ProjectTemplateLink>
    </ProjectCollection>
  </TemplateContent>
</VSTemplate>

VSTemplate(PCL,Android,iOS用) の変更

次に、ZIPを解凍したフォルダ内にあるPCL,Android,iOSのVSTemplateファイルを開き、TemplateDataに以下のCreateInPlaceを追記します。
追記しない場合、共有プロジェクトを参照できず、プロジェクトの作成に失敗する原因となります。

<CreateInPlace>true</CreateInPlace>

csproj の変更

Android,iOSの各csprojファイルを変更します。 以下の通り変更することで各プロジェクトでPCLプロジェクトが参照されるようになります。
$safeprojectname$ ではなく $ext_safeprojectname$ であることがポイント。

変更前

  <ItemGroup>
    <ProjectReference Include="..\MyXamarinFormsTemplate\MyXamarinFormsTemplate.csproj">
      <Project>{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}</Project>
      <Name>MyXamarinFormsTemplate</Name>
    </ProjectReference>
  </ItemGroup>

変更後

  <ItemGroup>
    <ProjectReference Include="..\$ext_safeprojectname$\$ext_safeprojectname$.csproj">
      <Project>{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}</Project>
      <Name>$ext_safeprojectname$</Name>
    </ProjectReference>
  </ItemGroup>

各テンプレートをまとめる

ここまで作成・変更したファイル(ZIPを除く)を全て1つのZIPファイルへ圧縮します。
※ここではMyTemplate.zipとしてZIPファイルを作成。 f:id:kenichiro246:20180615153836p:plain

Visual Studio への反映方法

MyTemplate.zipを ツール>オプション>プロジェクトおよびソリューション>場所>ユーザー プロジェクト テンプレートの場所 のパスに保存し、Visual Studioを起動または再起動します。
その後、プロジェクトの新規作成の画面を開くと、以下のとおり自分で作成したテンプレートが選択できるようになります。
f:id:kenichiro246:20180615152315p:plain

※ツリー内の「Cross-Platform」などでも表示させたい場合は、上記のテンプレートのパスに「Cross-Platform」などのフォルダを作成し、テンプレートのZIPファイルを保存すると以下のように選択できるようになります。 f:id:kenichiro246:20180615140036p:plain

テンプレートから実行

あとはテンプレートを選択し、OKボタンを押した後、実際にビルドしてみましょう。
設定が問題なければ、テンプレート化する前のソリューションの状態と同じように動くはずです。

Templateの削除方法

テンプレートを作成できるようになりましたが、削除も合わせて覚えておきましょう。
覚えると言っても配置したZIPファイルを削除するだけですが。
「ユーザー プロジェクト テンプレートの場所」に保存したZIPファイルを削除するだけで、新しいプロジェクトから選択できないようになります。

以上がPCLを含めたTemplateの作り方となります。
実際にはインストーラーまで作りたいのですが今回はここまで。
少し余裕が出てきたらインストーラーまで作ってみます。

当エントリーが良かったと思ったらスターのクリックをお願いします。

(続き)[Xamarin.Forms]Plugin.BLEを使用してペリフェラルの情報を取得する方法

このエントリーは、2017年のQiita アドベントカレンダー(22日)で書いたエントリーの続きです。
今更ですが。。。

概要

今回は、前回組み込んでいなかったDisconnectDeviceAsyncを追加します。
また、接続中のデバイスを切断するだけではネタが少なすぎるので、接続中のデバイスを取得するロジックも組み込んでみましょう。

ソースコード

public PeripheralsPage()
{
    InitializeComponent();

    _BluetoothLe = Plugin.BLE.CrossBluetoothLE.Current;
    _Adapter = _BluetoothLe.Adapter;
    _Adapter.ScanTimeout = 5000;
    _Adapter.DeviceDiscovered += (s, e) =>
    {
        _deviceList.Add(e.Device);
    };
    _Adapter.ScanTimeoutElapsed += (s, e) =>
    {
        foreach (var device in _Adapter.ConnectedDevices)
        {
            _deviceList.Add(device);
        }
    };
    ListView1.ItemsSource = _deviceList;
    AddSearchButton();
}

protected override async void OnAppearing()
{
    base.OnAppearing();

    var devices = _Adapter.ConnectedDevices;
    foreach (var device in devices)
    {
        await _Adapter.DisconnectDeviceAsync(device);
    }
}

解説

  • DisconnectDeviceAsync
    接続中のデバイスを切断するメソッドです。
    今回はどのタイミングで切断するか迷いましたがシンプルなサンプルにしたかったので、OnAppearingで切断するようにしました。
    OnAppearingは画面がロードされた時に発火するイベントであり、ServicesPageから戻ってきた際に、呼び出され、デバイスを切断するようにしています。

  • ConnectedDevices
    接続中のデバイスの一覧を取得するプロパティです。

  • ScanTimeoutElapsed
    StartScanningForDevicesAsync によるスキャンが終わった際に発火するイベントです。
    今回、DeviceDiscovered はアドバタイズ中のペリフェラルしか取得できないので、スキャンが完了後、ConnectedDevices で接続済のペリフェラルを表示するようにしています。
    スキャンはScanTimeoutで5,000ms(5秒)で設定しているため、5秒後に発火することになります。

結果

せっかくなので、DisconnectDeviceAsync しない場合のStatusと、する場合のStatusがどのように変わっているか比較した動きもご確認ください。
自宅のChromecastAudioに接続した場合のStatusの違いを見ていただければわかりやすいと思います。

DisconnectDeviceAsync しない場合

f:id:kenichiro246:20180120125117g:plain

DisconnectDeviceAsync する場合

f:id:kenichiro246:20180120124919g:plain

前回に引き続きBluetooth Low Energyについて書きましたがいかがでしょうか。
良ければStarやコメントをお願いします。