アプリが実行されている端末を識別するには?[ユニバーサルWindowsアプリ開発]WinRT/Metro TIPS

ASHWID(=アプリごとに特有のハードウェアID)を使用して、ユニバーサルアプリでアプリごとに個々のデバイスを管理する方法を解説する。

» 2014年09月11日 12時32分 公開
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

 アプリが実行されているデバイスを識別したいと思ったことはないだろうか? 例えば、ゲームのハイスコアをデバイスごとに管理したい、あるいは、動作可能な台数を制限したい(インストール可能台数はエンドユーザーあたりWindowsで81台、Windows Phoneで5台であり、変更できない)、といったような場合だ。しかし、デバイスの名称や型番などでは、同じデバイスを1人のエンドユーザーが複数所持している場合に区別できない。また、MACアドレスはエンドユーザーのプライバシーに関わるとして、取得する手段が用意されていない。そこで利用できるのが「ASHWID」だ。

 本稿では「ASHWID」を取得する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #89」からダウンロードできる。

事前準備

 ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Express 2013 for Windowsを使っている。

  • SLAT対応のPC*1
  • 2014年4月のアップデート*2適用済みの64bit版Windows 8.1 Pro版以上*3
  • Visual Studio 2013 Update 2(またはそれ以降)*4を適用済みのVisual Studio 2013(以降、VS 2013)*5

*1 SLAT対応ハードウェアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウェアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。

*2 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。

*3 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。

*4 マイクロソフトのダウンロードページから誰でも入手できる(このURLはUpdate 3のもの)。

*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションで構わない。Visual Studio Express 2013 with Update 3 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsストアアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。


用語

 本稿では、紛らわしくない限り次の略称を用いる。

  • Windows:Windows 8.1とWindows RT 8.1(2014年4月のアップデートを適用済みのもの)
  • Phone:Windows Phone 8.1

サンプルコードについて

 Visual Studio 2013 Update 2(およびUpdate 3)では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*6。そのため、本稿で紹介するVBのコードはユニバーサルプロジェクトではなく、PCL(ポータブルクラスライブラリ)を使ったプロジェクトのものである*7

*6 VB用のユニバーサルプロジェクトは、来年にリリースされるといわれているVisual Studio「14」からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。

*7 Visual Studio 2013 Update 2(またはUpdate 3)のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。PCLに置いたものは、コードだけでなくXAML(画面)やリソースディクショナリなども共通に利用できる。そこで別途公開のサンプルコードでも、VBはWindows用/Phone用/共通コード(PCL)の3プロジェクト構成とした。ユニバーサルプロジェクトで作らなくてもユニバーサルWindowsアプリはリリースできるのである(「WinRT/Metro TIPS:ユニバーサルプロジェクトで開発するには?」参照)。


ASHWIDとは?

 ASHWID(=App Specific Hardware ID、アプリごとに特有のハードウェアID)とは、エンドユーザーのプライバシーに配慮した上で、アプリがデバイスを識別するための仕組みである。アプリごとにASHWIDは異なるように設計されているため、アプリをまたいでハードウェアを追跡することはできない。

 ASHWIDはバイナリデータであって、長さは不定である。ただし、4byteの整数倍の長さであり、4byte単位で意味を持っている。4byteのうち、前半の2byteにはコンポーネントの種類が、後半の2byteにはコンポーネントから生成された値が格納されている(次の表)。

4byte中の前半2byteの値
=コンポーネントの種類
4byte中の後半2byteの意味
=コンポーネントの値
01 00 プロセッサのCPU ID(CPU IDそのものではなく、CPU IDから生成された値。以下同じ)
02 00 メモリのサイズ
03 00 ディスクデバイスのシリアル番号
04 00 ネットワークアダプター(ネットワークカードのMACアドレスなど)
05 00 オーディオアダプター
06 00 ドッキングステーション
07 00 モバイルブロードバンドデバイスID
08 00 Bluetoothアドレス
09 00 システムBIOS

 例えば、次の画像に示すASHWIDの冒頭部分の意味は、以下のようである。

  • 1行目: 03 00 FE 29−ディスクデバイスから生成された値(その値は「FE 29」)
  • 2行目: 05 00 D6 D7−オーディオアダプターから生成された値
  • 3行目: 05 00 B4 F6−同じくオーディオアダプターから生成された値(2つ目のオーディオアダプター)

 このように、同じコンポーネントが複数存在するときにはそのまま複数のデータが格納される(そのため、ASHWIDの長さは不定になる)。また、7行目にコンポーネント「01」があるなど、コンポーネントの並び順も不定である。

作成したサンプルアプリの画面(一部) 作成したサンプルアプリの画面(一部)
4byteごとに改行して表示している。

 なお、ここまでの説明で気付かれたと思うが、ハードウェアの構成が変更されたときにはASHWIDも変化する。従って、どのコンポーネントの変化を無視して同一のハードウェアだと判定するかを、アプリごとに設計する必要があるだろう。詳しくは、記事末尾に挙げたMSDNのドキュメントをご覧いただきたい。

ASHWIDを取得するには?

 HardwareIdentificationクラス(Windows.System.Profile名前空間)を利用すればよい。

 HardwareIdentificationクラスのGetPackageSpecificTokenメソッドを使うと、HardwareTokenオブジェクト(Windows.System.Profile名前空間)が得られる。HardwareTokenオブジェクトのIdプロパティ(Windows.Storage.Streams名前空間のIBufferインターフェースを実装している)に、ASHWIDのデータがバイナリで格納されている。それをbyte配列に読み取り、さらに16進数の文字列配列に変換して返すメソッドは次のコードのようになる。

public static string[] GetHardwareId()
{
  // HardwareTokenオブジェクトを取得する
  Windows.System.Profile.HardwareToken token = 
    Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null);

  // HardwareTokenオブジェクトからASHWIDをbyte配列に読み取る
  uint idLength = token.Id.Length;
  byte[] bytes = new byte[idLength];
  using (var reader = Windows.Storage.Streams.DataReader.FromBuffer(token.Id))
    reader.ReadBytes(bytes);

  // 読み取ったASHWIDを16進数の文字列配列に変換して返す
  return bytes.Select(b => b.ToString("X2")).ToArray();
}

Public Shared Function GetHardwareId() As String()

  ' HardwareTokenオブジェクトを取得する
  Dim token As Windows.System.Profile.HardwareToken = _
    Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(Nothing)

  ' HardwareTokenオブジェクトからASHWIDをbyte配列に読み取る
  Dim idLength As UInteger = token.Id.Length
  Dim bytes(idLength - 1) As Byte
  Using reader = Windows.Storage.Streams.DataReader.FromBuffer(token.Id)
    reader.ReadBytes(bytes)
  End Using

  ' 読み取ったASHWIDを16進数の文字列配列に変換して返す
  Return bytes.Select(Function(b) b.ToString("X2")).ToArray()

End Function

ASHWIDをbyte配列として取得し、されに16進数の文字列配列に変換して返すメソッド(上:C#、下:VB)
ここでは16進数の文字列配列に変換しているが、実際のアプリではbyte配列のまま扱って構わない。
なお、C#のコードには冒頭に「using System.Linq;」も必要だ。

実行結果

 C#の共有プロジェクト(VBではPCL)にユーザーコントロールを置き、そこにTextBlockコントロール(Windows.UI.Xaml.Controls名前空間)を配置した。前出のGetHardwareIdメソッドを使って取得したASHWIDを、そのTextBlockコントロールの1行に4バイト分ずつ表示するようにコードを作成した。また、Windowsでは、ログオンユーザー名も表示するようにした(次の画像)。詳細は、別途公開のサンプルコードをご覧いただきたい。

作成したサンプルアプリ(Windows 8.1)
作成したサンプルアプリ(Windows Phone 8.1エミュレーター) 作成したサンプルアプリ(上:Windows 8.1、下:Windows Phone 8.1エミュレーター)

 ここでASHWIDの挙動を調べておこう。以下、Windowsについてだけ掲載する(Phoneも同様である)。上に掲載した画像のWindowsアプリの状態を基準として、それとの対比でお見せする。なお、作成したアプリを別のアカウントやデバイスでテストするためには、パッケージを作成してそこからインストールする必要がある(ストアにアップロードできるパッケージでなくてもよい)*8*9

*8 別途公開のサンプルコードのWindows用プロジェクトには、デジタル署名に必要なファイルが入っていない。そのため、そのままパッケージを作成しようとするとエラーになる。次の手順で必要なファイルを作成してから、Windows用のパッケージを作成してほしい。

  • マニフェストファイル「Package.appxmanifest」を開き、[パッケージ化]タブの[証明書の選択]ボタンをクリック
  • 出てきた[証明書の選択]ダイアログで、[証明書の構成]ドロップダウンから[テスト証明書の作成]を選ぶ。すると[テスト証明書の作成]ダイアログが表示されるので、[発行者共通名]とパスワード(空のままでも可)を入力して[OK]ボタン。戻ってきた[証明書の選択]ダイアログでも[OK]ボタン
  • 以上で、デジタル署名に必要なファイル(拡張子は「.pfx」)が作成され、プロジェクトに組み込まれた。あとは、メニュー[ストア]−[アプリ パッケージの作成]を選び、[Windows ストアにアップロードするパッケージを作成しますか?]の選択で[いいえ]を選んでパッケージを作成すればよい

*9 VS 2013を使っていないWindowsにインストールするためには、開発者用ライセンスを手作業で導入しておく必要がある。詳しくはMSDNの「開発者用ライセンスの取得 (ストア アプリ)〜コマンド プロンプトからの開発者用ライセンスの取得」を参照


 ASHWIDはデバイスを識別するための仕組みであるから、別のデバイスでは異なる値になる(次の画像)。

異なるデバイスでは異なるASHWID(左:基準、右:別のハードウェア) 異なるデバイスでは異なるASHWID(左:基準、右:別のハードウェア)
別のハードウェアで実行すると、ASHWIDは異なる値になる。

 同じハードウェア上ならば、利用しているエンドユーザーが異なっていても同じ値が得られる(次の画像)。

異なるエンドユーザーでも、同じデバイスならば同じASHWID(左:基準、右:別のアカウントで実行) 異なるエンドユーザーでも、同じデバイスならば同じASHWID(左:基準、右:別のアカウントで実行)
ログインしているアカウントは異なっているのだが、同じハードウェアで実行しているため同じASHWIDになる。

 同じハードウェアと同じアカウントであっても、アプリが異なるとASHWIDは異なる値になる(次の画像)。

同じデバイスと同じエンドユーザーでも、別のアプリでは異なるASHWID(左:基準、右:別のアプリ) 同じデバイスと同じエンドユーザーでも、別のアプリでは異なるASHWID(左:基準、右:別のアプリ)
左はC#版、右はVB版である。アプリが異なれば、違うASHWIDになる。

まとめ

 デバイスを識別するためにASHWIDを利用できる。ただし、アプリをまたいでの追跡には利用できないことと、ハードウェアの構成変更でASHWIDも変化することに注意が必要だ。

 ASHWIDの扱いについては、次のドキュメントも参照してほしい。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。