【C4】Delphi/C++テクニカルセッション「多様化するスマートデバイスをビジネスアプリに活用するためのアーキテクチャと開発のヒント」
Embarcadero Technologies, Inc.
Manager, QA, Documentation, and Localization
新井 正広

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

1
2

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

はじめにこのセッションの内容• キーワード– スマートデバイス– ビジネスアプリ• 企業内で使われるアプリ– データとの連携  データベース接続• このセッションでフォーカスすること– データベース接続以外で「スマートデバイス利用」を念頭に「データと連携する」技術

3

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

2
4

スマートデバイス
対応の方向性本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

Delphi / C++Builder ベースの典型的なアプリ• 企業情報システム– Windows ベースのクライアント• キーボード、マウス、高解像度モニタ、ネットワークなどの入出力– 多機能なユーザーインターフェース– バックエンドのデータベースへの接続– 帳票などへの出力• 科学技術計算など、CPU パワーが重要なもの• 不特定多数のユーザーに配布するもの– インストーラ不要（実行形式ファイルのみ配布）
5

モバイルへの対応• モバイルならではの活用方法はあるのか？
– モバイルの「機能」を利用することが「目的」ではない

• 例えば
– カメラ
– GPS
– （ほぼ）どこでもネットワークに接続（3G / 4G / LTE)– プッシュ通知6モバイル展開のアイデア• 在庫管理システムの端末– 商品情報をバーコード撮影– 不良品の写真を撮影– 商品の情報を、画像とともに登録• 自動車保険（事故現場のレポート）– 事故現場、車両の写真– 位置情報– 相手の運転免許の写真– 携帯ネットワーク経由で事故情報のレポート
7

モバイル展開のアイデア• 営業支援システム– 訪問先の位置情報を利用して– 訪問記録の登録• 手入力するのではなく、位置情報から絞り込み– 近所の案件情報の検索• ついでに訪問できる案件は？

– 緊急案件を会社から通知

8

モバイル展開のアイデア• どのような機能を利用できるかリサーチ• どのような機能を組みこくことが妥当か検証

9

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

モバイルへの対応• Delphi / C++Builder でモバイル対応！
• では、同じ機能をそのまま移植？
– 画面サイズの違い– キーボード、マウスなどの入力デバイスの違い– データベースへの接続• クライアントライブラリの有無– ネットワーク環境の違い– 帳票への出力は？

• モバイル端末上で同じユースケースを考えるのか？
10どのような機能を実装するにせよ。。。
• UI とロジック、データアクセスの分離– データモジュールを利用する• デスクトップ向けとモバイル向けは UI の構成が大きく異なる• アプリケーション間での共通機能の共有• 複数のフォームファクターのサポート– フォームの継承

11マルチプラットフォーム環境向けのアプリケーションの構造• バックエンドとの接続は「データモジュール」へ– データモジュール自体は初期の Delphi からある仕組
み– 同じプラットフォームでもデバイスごとに UI を最適化

• テストプロジェクトの作成も視野に• Prototype からの置き換え

12

213

「データと連携する」技術の一般的な選択肢

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

「スマートデバイス」を念頭に「データと連携」するための選択肢• DataSnap– バックエンドデータベースをDataSnapでカプセル化• アプリケーション テザリング– アプリケーション間で、アクション・データを共有• リモートマシンで公開されているアクションの呼び出し• データ・ストリームの送受信• REST (Representational state transfer)– Google Apps, Salesforce など、主要なプラットフォー
ムがREST での接続をサポート• BaaS (Backend As Service) サービスの活用
14DataSnap• 既存のデータベースに接続するのであれば、開発は最も容易

15

316

アプリケーション
テザリング

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

アプリケーション テザリング• アプリケーション間で– アクションを共有– データ・ストリームの送受信• 利用方法– デスクトップアプリケーションをリモート制御– デスクトップアプリケーションへの入力支援• カメラなど• バーコードの読み取り– モバイル端末とのデータの共有
17

アプリケーション テザリング• 同一サブネット上で動作するアプリ同士の連携– 連携するプラットフォームは問わない– 1:n 接続でも構わない

18

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

アプリケーション テザリング• テザリングを通じた機能の公開– TTetheringManager• 同一サブネット上にある TTetheringManager を検出• パスワードによるアプリケーションの認証– TTetheringAppProfile• アプリケーションが所属するグループを定義• アプリケーションが公開／利用するアクションを定義• アプリケーションが公開／利用するリソースを定義– データ（文字列、数値など）– ストリーム19

20

リモートアプリケーションの検出と接続• グループ名を定義し自動的にペア設定– TTetheringAppProfile.Group プロパティを設定– TTetheringManager.AutoConnect() を呼び出し• 接続パスワードを設定– TTetheringManager.Password プロパティを設定– 設計時に静的に設定 or 実行時に動的に設定• 手動でリモートアプリケーションに接続
21

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

1) TTetheringManager を探す
procedure TFmxTetheringAppForm.RefreshManagers;var
i: Integer;
begin// 既に接続している TTetheringManager があれば、ペア設定を解除
for i := TetheringManager1.PairedManagers.Count - 1 downto 0 do
TetheringManager1.UnPairManager(TetheringManager1.PairedManagers[i].ManagerIdentifier);// 新たに TTetheringManager を探す
TetheringManager1.DiscoverManagers();
end;22

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

2) TTetheringManager とペア設定する
procedure TFmxTetheringAppForm.TetheringManager1EndManagersDiscovery(const Sender: TObject;
const RemoteManagers: TTetheringManagerInfoList);var
RemoteManager: TTetheringManagerInfo;
beginfor RemoteManager in RemoteManagers do
begin// 接続先の TTetheringManager のプロパティを確認してから接続
if RemoteManager.ManagerText = 'DeveloperCampDemo' thenTetheringManager1.PairManager(RemoteManager);
end;end;233) TTetheringAppProfile と接続する
procedure TFmxTetheringAppForm.TetheringManager1EndProfilesDiscovery(const Sender: TObject;
const RemoteProfiles: TTetheringProfileInfoList);var
RemoteProfile: TTetheringProfileInfo;
begin// 接続先の TTetheringAppProfile のプロパティを確認してから接続する
for RemoteProfile in RemoteProfiles do
begin// リモート側の TTetheringAppProfile.Text は自分で事前に設定しておく
if RemoteProfile.ProfileText = 'Glass 1' thenTetheringAppProfile1.Connect(RemoteProfile);
end;end;24

アプリケーション テザリング• アクションの公開– アプリケーションでアクションを使用– TTetheringAppProfile に公開するアクションを定義– 既に定義されているアクションとTTetheringAppProfile で新たに定義したアクションを接続

25

アプリケーション テザリング• 公開されているアクションを利用– 公開するアクションに相当するアクションを定義– TTetheringAppProfile に利用するアクションを定義• Kind プロパティを Mirror に変更– 定義したアクションと TTetheringAppProfile に定義したアクションを接続

26

共有リソースの定義• 共有できるリソース
– データ
• 文字列
• 数値 (Integer, Double, Int64)• 真偽値 (Boolean)– ストリーム27共有されたリソースを取得する• 同名のResources[] プロパティを作成する– Kind プロパティを Mirror に設定する– Kind プロパティ以外は同じ値に設定しておく

28

4) リソースを公開する
procedure TFmxTetheringAppForm.ButtonSendImageClick(Sender: TObject);begin
if not Assigned(FStream) thenFStream := TMemoryStream.Create;
ImageToSend.Bitmap.SaveToStream(FStream);
FStream.Position := 0;
TetheringAppProfile1.Resources.FindByName('Picture').Value:= FStream;
end;

29

5) リソースの変更を取得する
procedure TMobileForm.TetheringAppProfile1PictureResourceReceived(const Sender: TObject; const AResource: TRemoteResource);
begin
ImageReceivedPicture.Bitmap.LoadFromStream(AResource.Value.AsStream);
end;

30

331

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

REST

REST(Representational State Transfer)• ステートレスな接続– HTTP / HTTPS による接続• URI でリソースを特定– http://example.com/users/masahiro/• メソッド（動詞）で動作を規定– GET, POST, PUT, DELETE• JSON, XML などのデータを利用• 多くのベンダーが開発者向けのAPIをRESTで提供– Google, Amazon, Salesforce, JIRA,
32

「つながる」仕組みとしての REST
• メリット– 構造が単純– 多くのベンダーが REST をサポート– プラットフォーム非依存• 難しい点– 実装の詳細はベンダー依存• ユーザー認証などの実装はベンダーごとに異なる• 一般的なデータベース操作などに対する標準が無い• コードのベンダー間での使い回しは（ちょっと）難しい33

「つながる」仕組みとしての RESTの利用例• 企業の情報システム– Salesforce.com• クラウドサービス– Google Apps, Amazon, Azure• ソーシャルネットワーク– Facebook, Twitter• データベース製品• 変わったところでは、– Jira, MediaWiki, Jenkins
34

REST サービスを提供する• RESTful な DataSnap サーバーとして実装する。
• メリット– TCP/IP 経由接続とほぼ同じ手順でサーバーを作成– クライアントもウィザードで生成– Delphi / C++Builder 以外のクライアントも、容易にサポート可能35

REST を使用して、クラウドサービスに接続する• クラウドサービスを使用する場合の手順– 開発者として登録– アプリケーションごとにApplication ID, Secretを取得

https://play.google.com/store/search?q=twitter&c=apps
36

REST を使用して、クラウドサービスに接続する• Application ID, Secret はあくまでも、アプリの識別• 個人情報にアクセスする場合– ユーザー名などはアプリで管理しない– O-Auth 2.0 などの仕組みを利用してユーザー認証

37

4
38

BaaS (Backend As Service)
サービスの活用

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

BaaS の活用
• モバイルアプリで一般的に利用される機能をまとめて提供– データ管理– ユーザー管理・アクセス管理– プッシュ通知• モバイル、デスクトップの両方からアクセス可能• 自前で公開サービスを作成する必要なし– ユーザー環境におけるセキュリティ対策を簡略化

39

Baas プロバイダーへの接続TBackgroundUser

ユーザーアカウント

TBackgroundQuery

データの取得TBackgroundStrage

抽象化されたデータアクセス

TBackgroundFile

ファイル保存TBackgroundPush

プッシュ通知のリクエスト

TPushEvents

プッシュ通知イベント

TKinveyProvider

TParseProvider

40

サンプルデータ

41

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• データの作成
FEntity1, FEntity2: TBackendEntityValue;//----------------------------------Var
SessionData: TSessionData;
begin
SessionData := TSessionData.Create;
try
SessionData.ID:= EditID.Text;
SessionData.Title:= EditTitle.Text;
SessionData.Speaker := EditSpeaker.Text;
BackendStorage1.Storage.CreateObject<TSessionData>('Session', SessionData, FEntity1);
finally
SessionData.Free;
end;
end;
42

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• データの参照
var
SessionData: TSessionData;
ObjectList: TBackendObjectList<TSessionData>;
Query: TArray<string>;
begin
Query := TArray<string>.Create('sort=ID'); //Kinvey
ObjectList := TBackendObjectList<TSessionData>.Create;
BackendStorage1.Storage.QueryObjects<TSessionData>('Sessions', Query, ObjectList);
for SessionData in ObjectList do
begin
LabelID.Text:= SessionData.ID;
LabelTitle.Text:= SessionData.Title;
LabelSpeaker.Text := SessionData.Speaker;
end;
43

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• データの更新
FEntity1, FEntity2: TBackendEntityValue;//----------------------------------Var
SessionData: TSessionData;
begin
SessionData := TSessionData.Create;
try
SessionData.ID:= EditID.Text;
SessionData.Title:= EditTitle.Text;
SessionData.Speaker := EditSpeaker.Text;
BackendStorage1.Storage.UpdateObject<TSessionData>(FEntity1, SessionData, FEntity2);
finally
SessionData.Free;
end;
end;
44

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• データの削除
FEntity1, FEntity2: TBackendEntityValue;//----------------------------------begin
BackendStorage1.Storage.DeleteObject(FEntity2);
end;

45

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• ファイルのアップロード
var
AFile: TBackendEntityValue;
Stream: TFileStream;
begin
Stream := TFileStream.Create(‘template.xml', fmOpenRead);try
BackendFiles1.Files.UploadFile(‘template.xml’,// BaaS サービス上でのファイル名
Stream,// アップロードするストリーム’application/xml',// Content-TypeAFile);// [out] アップロードしたファイルの情報
finally
Stream.Free;
end;
end;

46

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

TBackend*コンポーネントを利用する• ファイルのダウンロード・消去
var
AFile: TBackendEntityValue;
Stream: TFileStream;
begin// BackendFiles1.Files.UploadFile(…);
Stream := TMemoryStream.Create;
try
TDownloadURL.DownloadRawBytes(AFile.DownloadURL, Stream);Stream.SaveToFile(‘template2.xml');
finally
Stream.Free;end;
BackendFiles1.Files.DeleteFile(AFile);
end;
47

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

プッシュ通知の利用• Parse あるいは Kinvey を経由した接続• iOS および Android 向けの通知をサポート– 通知センターへのメッセージ送信– アプリケーションの参照を促す• 単純なメッセージの送信• データーの変更によるメッセージの自動送信

48

「プッシュ通知」を利用する
GoogleCloud
Messaging

iOS Push
Notification※個々のサービスに対するアカウントが必要
49

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

「プッシュ通知」の受信• データの受信そのものは単純
procedure TForm1.PushEvents1PushReceived(Sender: TObject;
const AData: TPushData);
begin
ListView1.Items.Add.Text := AData.Message;end;• しかし、アプリは休止している可能性が高い
procedure TForm1.FormActivate(Sender: TObject);beginif Assigned(PushEvents1.StartupNotification)and (PushEvents1.StartupNotification.Message <> '') then
ListView1.Items.Add.Text:= PushEvents1.StartupNotification.Message;
end;

50

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

6
51

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

まとめ