記事公開日
Power AppsアプリにQRコードを表示する方法

こんにちは。システムソリューション営業本部の吾妻です。
Power Appsを利用したシステム化では、QRコードを利用するものが多々あります。よくあるテーマを以下に挙げます。
・在庫管理
・備品管理
・イベント入退場管理(受付アプリ)
・順番待ちシステム
・オフィス在席管理
Power Appsでは、QRコードを読み取るための「バーコードリーダーコントロール」は用意されていますが、QRコードを動的に生成して表示するためのコントロールは存在しません。そこで今回は、Power Appsのキャンバスアプリやモデル駆動型アプリにQRコードを表示するための実装方法をご紹介したいと思います。
QRコードを表示する方法3選
Power AppsでQRコードを表示するための方法として、以下の3通りが考えられます。
・画像コントロールのImageプロパティに、外部のQRコード生成APIのURLを設定する
・外部のQRコード生成APIを呼び出すために、カスタムコネクタを利用する
・PCFで独自のコントロールを作成し、キャンバスアプリやモデル駆動型アプリに組み込む
次項では、それぞれの方法について、具体的な実装内容を見ていきたいと思います。
画像コントロール
キャンバスアプリの画像コントロールでは、表示する画像を指定するためのプロパティとして、Imageプロパティが用意されています。Imageプロパティには、DataverseやSharePointの画像列を指定することも、外部のWebサイトに掲載されている画像ファイルのURLを指定することも、データURLを指定することもできます。そのため、画像データそのもの(PNG形式やSVG形式)やデータURLを本文として返すようなQRコード生成APIを利用する場合、このImageプロパティにAPIのエンドポイントURLを直接指定することで、QRコードを表示することができます。
APIレスポンスの形式
「画像データそのもの」の例としては、以下のようなContent-Typeヘッダーと本文を持つAPIレスポンスが考えられます。種類 | Content-Typeヘッダー | 本文の形式 |
SVG画像 | image/svg+xml | テキスト(XML文字列) |
PNG画像 | image/png | バイナリ(PNG形式) |
データURL
データURLとは、「data:」スキーム、「MIMEタイプ」(および文字コードやbase64トークン)、「データ」からなる文字列です。以下の表のPNG画像の行のように、バイナリデータをデータURLで表現する場合には、Base64エンコードすることで文字列表記に変換したものを「データ」に指定します。一方で、テキストデータをデータURLで表現する場合には、必ずしもBase64エンコードする必要はありません。なので、SVG画像をデータURLで表現する際には、「データ」部分に直接XML文字列を指定することもできます(ただし、マルチバイト文字を含む場合など、URLエンコードは必要なことがあります)。ブラウザで新規タブを開いて、アドレスバーに下表のデータURLを入力してEnterキーを押すと、デコードされた状態で画像やテキストが表示されるかと思います。
種類 | データURL | 結果 |
PNG画像 | data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkQAAAJEAQAAAADfmwb3AAABbklEQVR4nO3aW47CMAwF0O6A/e+SHTAaaOQ8B41ArSud+4FI4hz+sFXYHl/KfSORSCQSiUQikUgkEolEIpFIJBLpitLW5/a7d3uVleVYQiKRSKQ0Uuw3yzCXJSQSiURKIs2awbsSEolEImWXYrInkUgk0qWkfbntbYFEIpFI2aUBHl/mN0gkEol0vtRlJo0lJBKJREoizXOvJ/s/60gkEol0tlRuRZ7b9bd/eea+H6w6AolEIpGOl+oLzd6SI5FIJFImaXm1ezef9kkkEol0tlRfmM/uTUcgkUgkUjLpWTGY0QIKEnUkEolEyiWNCWn5YSQSiURKIm19YsZv+sCgk0gkEimJ1P1Yupjs42DdEUgkEol0khQVdUfYa0tH6A5IJBKJlFjqEoN+FxKJRCKllbrTASGRSCRSHmmA47nMPzsCiUQikQ6XujS3huX7/7STSCQS6VDps5BIJBKJRCKRSCQSiUQikUgkEon0uI70A2D0W+PB+bbiAAAAAElFTkSuQmCC | PNG(qes) |
テキスト | data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%20baseProfile%3D%22full%22%20shape-rendering%3D%22crispEdges%22%20width%3D%22580%22%20height%3D%22580%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22580%22%20height%3D%22580%22%20fill%3D%22%23FFFFFF%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%2280%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%2280%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%2280%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22360%22%20y%3D%2280%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22200%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22280%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22320%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22360%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22480%22%20y%3D%22100%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22120%22%20y%3D%22120%22%20width%3D%2260%22%20height%3D%2260%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22260%22%20y%3D%22120%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22400%22%20y%3D%22120%22%20width%3D%2260%22%20height%3D%2260%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%22140%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22160%22%20width%3D%2280%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22180%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22280%22%20y%3D%22180%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22320%22%20y%3D%22180%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22200%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22360%22%20y%3D%22200%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22260%22%20y%3D%22220%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%22240%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22280%22%20y%3D%22240%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22380%22%20y%3D%22240%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22480%22%20y%3D%22240%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22260%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22260%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22320%22%20y%3D%22260%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22420%22%20y%3D%22260%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22120%22%20y%3D%22280%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22200%22%20y%3D%22280%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22280%22%20y%3D%22280%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22360%22%20y%3D%22280%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22420%22%20y%3D%22280%22%20width%3D%2260%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22300%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22160%22%20y%3D%22300%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22300%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22340%22%20y%3D%22300%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%22320%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22160%22%20y%3D%22320%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22320%22%20width%3D%2240%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%22320%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22380%22%20y%3D%22320%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22420%22%20y%3D%22320%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%22340%22%20width%3D%2220%22%20height%3D%2240%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22440%22%20y%3D%22340%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22360%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22360%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22340%22%20y%3D%22360%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22400%22%20y%3D%22360%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22460%22%20y%3D%22360%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22380%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22200%22%20y%3D%22380%22%20width%3D%2220%22%20height%3D%22100%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22380%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%22380%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22380%22%20y%3D%22380%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22440%22%20y%3D%22380%22%20width%3D%2260%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22120%22%20y%3D%22400%22%20width%3D%2260%22%20height%3D%2260%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22400%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22340%22%20y%3D%22400%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22400%22%20y%3D%22400%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22440%22%20y%3D%22400%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22420%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22420%22%20y%3D%22420%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22440%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22320%22%20y%3D%22440%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22360%22%20y%3D%22440%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22460%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22300%22%20y%3D%22460%22%20width%3D%2280%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22420%22%20y%3D%22460%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%2280%22%20y%3D%22480%22%20width%3D%22140%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22260%22%20y%3D%22480%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22320%22%20y%3D%22480%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22380%22%20y%3D%22480%22%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3Crect%20x%3D%22440%22%20y%3D%22480%22%20width%3D%2240%22%20height%3D%2220%22%20fill%3D%22%23000000%22%2F%3E%3C%2Fsvg%3E | SVG(qes) |
一般公開されているAPIの例
一般向けに公開されているQRコード生成サービスの例として、以下のようなものが挙げられます。括弧内のリンクから、Microsoft公式資料の「すべてのコネクタの一覧」で公開されているサードパーティー製コネクタのページを開くことができます。・GoQR(コネクタ)
・OpenQR(コネクタ)
独自APIの構築例
個人名、メールアドレス、一意なIDなどを含むQRコードを生成したいときは、第三者に情報を渡すわけにいかないので、独自にAPIを用意する必要があります。Azureを利用している場合、Azure Functionsを利用すると、手っ取り早く実装できます。例えば、C#で実装する場合だと、QRCoderというNuGetパッケージを活用すると、パラメーターさえ渡してしまえば、PNGやSVG、ASCII、Base64エンコードなどの各種形式のQRコードを簡単に取得することができます。

Azure以外では、Cloudflare WorkersなどのFaaS(Function as a Service)を利用するのがおすすめです。例えば、Node.jsで実装する場合には、qrcodeやqrcode-svgといったnpmパッケージを活用することで、C#の場合と同様に、様々な形式でQRコードを出力させることができます。たいていのFaaSでは、GitHubからCI/CDする機能が用意されているので、FaaSがサービス終了しても簡単に他サービスに移行できるのもメリットの1つです(最近だと、Glitchのサービス終了がニュースになっていましたが、ソースコードを変更することなく、Cloudflare Workersに容易に移行できました)。
カスタムコネクタ
画像データそのものではなくJSON形式でQRコードを返すようなREST APIや、認証を求められるREST APIを利用する場合、画像コントロールに直接表示させるのではなく、カスタムコネクタを利用してQRコードを取得してから、必要に応じて画像コントロールやHTMLテキストコントロールに表示するという方法をとります。
カスタムコネクタから呼び出すための独自APIを用意する場合、Azure Functionsを利用するのが便利です。前項の画像コントロールに直接表示させる方法とは異なり、キャンバスアプリ側から認証情報を渡すことができるので、それを受け取るAPI側でも、Easy Authを利用して、Entra IDによる認証を追加することができます。
PCF
PCF(Power Apps Component Framework)を利用して、QRコードを表示する独自のコントロールを作成することができます。作成したコントロールは、キャンバスアプリやモデル駆動型アプリ、Power Pagesサイトに組み込むことができます。カスタムコンポーネントの中でQRコードを生成するようなソースコードを組み込むことで、前述の2つの方法のように外部APIに依存することなく、QRコードを表示することができます。
カスタムコンポーネントは、JavaScriptまたはTypescriptを利用してReactコンポーネントを作り、Power Platform環境にデプロイすることで、キャンバスアプリやモデル駆動型アプリから利用できるようになります。Reactコンポーネントを実装する際には、npmパッケージを活用することで、大量のソースコードを書かなくても欲しい機能を実現することができます。

PCFを利用してカスタムコンポーネントを作成する手順の詳細については、以下の記事でご紹介しています。
PCFを利用して作成したコントロール(コンポーネント)を、キャンバスアプリに組み込んだ場合、1点注意が必要なことがあります。キャンバスアプリを「再生」する際には特に変わったところはないのですが、アプリを「編集」する際には、以下のような警告ダイアログが表示されることがあります。カスタムコンポーネントを作る人と使う人が同一であれば気にする必要はありません(何か問題があっても自己責任というだけです)が、PCF Galleryに公開されているものをダウンロードしてくる場合も含めて、カスタムコンポーネントを作る人と使う人が異なる場合は、組み込まれているコードコンポーネントが信頼できるものかどうか、自分で判断する必要があります。

まとめ
今回は、Power Appsのキャンバスアプリやモデル駆動型アプリにQRコードを表示するための実装方法を、簡単にご紹介しました。QES では Power Platform の開発支援、QAサポート、開発者教育、ガバナンス整備など、組織で Power Platform を活用するためのサポートを包括的にご提供しています。Power Platform 活用についてご興味がある/利用中だが課題を感じていらっしゃるお客様はまずはお気軽にお問い合わせください。このブログで参照されている、Microsoft、Windows、その他のマイクロソフト製品およびサービスは、米国およびその他の国におけるマイクロソフトの商標または登録商標です。
QRコードは(株)デンソーウェーブの登録商標です。
Cloudflare、Cloudflareのロゴ、およびCloudflare Workersは、米国およびその他の管轄区域におけるCloudflare, Inc.の商標および/または登録商標です