Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Meetup11 contacts api読んでみた

459 views

Published on

FxOSコードリーディングミートアップ#11の資料

Published in: Software
  • Be the first to comment

  • Be the first to like this

Meetup11 contacts api読んでみた

  1. 1. # Contacts API読んでみた 株式会社グローバルサイバーグループ マネージャ 藪下正美
  2. 2. # はじめに
  3. 3. ## 自己紹介 •藪下正美 •組み込み系の会社でスマホ作ってる人 •OSとかコンパイラとかの理屈が好きでいつの間にか数学 基礎論とか形式言語とか形式手法とか論理学とかに足を 踏み入れてしまった人 •最近アカデミック分が足りてなくてモヤモヤしてるので TaPLとかSICPとかそこらへんの読書会をやりたがって いる
  4. 4. ## 会社紹介 •株式会社グローバルサイバーグループ –http://www.gcg.bz•関西出身の組み込み系ソフトハウス •勉強会支援やってます。会議室借りたい、プロジェクタ借り たい、登壇してほしいなど気軽にご相談ください。 –http://www.gcg.bz/labo_blog/?page_id=943•質問受け付けてます。ブログネタください。 –http://www.gcg.bz/labo_blog/?page_id=945•本日の懇親会は株式会社グローバルサイバーグループの支援 を受けています。
  5. 5. ## 今日のアジェンダ •Contacts APIとは •Firefox OSの連絡帳アプリから使い方を見てみる –連絡先の保存 –連絡先の検索 –連絡先の全件取得 –連絡先の削除 •Contacts APIの実装のお話 –Contacts APIの概要図 –Contacts APIの流れ –Contacts APIのDBエントリデータ構造 •資料書いてみたら前半がすごい長くなっちゃったのでAPIの実装の話は後 日やります
  6. 6. ## 今日のコードリーディングに使ったソース コード •今回のコードリーディングはちょっと古いソースですが 以下のURLのを使ってます –http://reading.fxos.org/source/
  7. 7. # Contacts APIとは •Contacts APIは連絡先情報を扱うAPIです •Gaiaでは連絡帳アプリやSMSアプリで使われます –ざっくりと保存、読み込み、更新、削除のインターフェイスを 備えています
  8. 8. # Firefox OSの連絡帳アプリから使い方を見 てみる •もともと自作のアプリで使うための調べものですがせっ かくなのでコードリーディングしてみましょう •今回のターゲットはContacts APIなので連絡帳アプリか ら読んでみます –B2G/apps/communications/contacts
  9. 9. ## パーミッション •まずはパーミッションです •パーミッションのリストはMDNで見てください –https://developer.mozilla.org/ja/Apps/App_permissions
  10. 10. ### Gaiaの連絡帳アプリのパーミッション •B2G/gaia/apps/communications/manifest.webapp "name": "Communications", "description": "Gaia Communications", "type": "certified", "launch_path": "/", : (snip) : "permissions": { : (snip) : "contacts":{ "access": "readwrite" }, : (snip) : },
  11. 11. ## Contacts APIのパーミッション •apps/communications配下はいくつかのアプリを含んでい るので沢山パーミッションがありますがキモはここです •B2G/gaia/apps/communications/manifest.webapp"contacts":{ "access": "readwrite" }, •見たままContacts APIのパーミッションです •連絡帳アプリでは読み書きどちらも要求しています –SMSアプリなどでは読み込みだけ要求しています –他にも初期設定アプリが読み書き、メールや電話アプリは読み込み のみで使ってます "contacts":{ "access": "readwrite" },
  12. 12. ### Gaiaの連絡帳アプリの特権 •もうひとつここも勘所です •B2G/gaia/apps/communications/manifest.webapp"type": "certified", •これはアプリ特権の設定です •Gaiaで定義されているプリインアプリなのでcertifiedが設定 されています •ユーザ定義のアプリだとここはprivilegedを使うことになり ます
  13. 13. ### パーミッションまとめ •Contacts APIを使用する際はpermissions属性に contacts属性の設定が必要です –contacts属性にはaccess属性を設定します –access属性にはreadonlyあるいはreadwriteを設定します •特権が必要なのでtype属性にprivilegedかcertifiedの設 定が必要です –privilegedの場合プロンプトが出ます
  14. 14. ## 連絡先の保存 •連絡先の保存を見ていきます •MDNの解説は以下を見てください –https://developer.mozilla.org/en- US/docs/Web/API/Contacts_API#Adding_a_contact
  15. 15. ### 保存処理 •B2G/gaia/apps/communications/contacts/js/export/sim.jsvar_updateContactSimSource= function _updateContactSimSource(theContact, iccContact, cb, errorCb) { if (!iccContact) { window.console.warn('No IccContact provided'); cb(); return; } theContact.url = theContact.url || []; theContact.url.push(_generateIccContactUrl(iccContact.id, _getIccId())); varreq= navigator.mozContacts.save(theContact); req.onsuccess= cb; req.onerror= function() { errorCb(req.error); }; };
  16. 16. ### 保存APIの呼び出し •Contacts APIを使ってるのはここですね •B2G/gaia/apps/communications/contacts/js/export/sim.jstheContact.url = theContact.url || []; theContact.url.push(_generateIccContactUrl(iccContact.id, _getIccId())); varreq= navigator.mozContacts.save(theContact); req.onsuccess= cb; req.onerror= function() { errorCb(req.error); }; •連絡先情報を渡してDOMRequestを受け取っているだけのシンプルな呼び出しですね •reqという変数に返り値を受けてonsuccessとonerrorを設定しているこの形はWebAPIの基本形の 一つです –処理に時間のかかるAPIやchromeプロセスに処理を要求するAPIにはDOMRequestやその派生オブジェクトを返す ものがたくさんあります –DOMRequestは非同期に動作するAPIの処理終了イベントを表すオブジェクトです
  17. 17. ### 保存APIの引数 •保存APIに渡されているオブジェクトがどんな値を持っ ているか見ていきます
  18. 18. #### mozContacts.saveの使用個所からさ かのぼる1•まず_updateContactSimSourceのtheContact出所を確認します •結論から言うとここから追うのははずれだったので細かくソースコードは見せませ ん ContactsSIMExport._updateContactSimSourct(theContact) ->ContactsSIMExport._doExport(contacts[step]、contactsは ContactsSIMExportのプロパティ) ->ContactsSIMExport.setContactsToExport(引数のctsがcontactsに設定さ れる) ->ContactsExporter._start (contacts、ContactsExporterのプロパティ) ->ContactsExporter._init(theContacts、連絡先IDの配列) •ここで引数の連絡先IDを持つ連絡先データを配列にしています •ですが連絡先データの出所がmozContacts.find()で取ってきた値なので使ってい るシーンがなくて残念な感じですね
  19. 19. #### mozContacts.saveの使用個所からさ かのぼる2•別の使用個所から追います •B2G/gaia/apps/communications/contacts/js/views/details.jsvarrequest = navigator.mozContacts.save(utils.misc.toMozContact(contact)); •utils.misc.toMozContactで連絡先情報を作っているようなので中身を見てみると •B2G/gaia/shared/js/contacts/import/utilities/misc.jsutils.misc.toMozContact= function(contact) { varoutContact= contact; if (!(contact instanceofmozContact)) { outContact= new mozContact(contact); outContact.id = contact.id || outContact.id; } return outContact; }; •new mozContactが連絡先情報みたいですね
  20. 20. #### 連絡先情報オブジェクト •mozContact何者?と思ったらwebidlを探しに行くのがお作法ですよね! •B2G/gecko/dom/webidl/Contacts.webidl[Constructor(optional ContactPropertiesproperties), JSImplementation="@mozilla.org/contact;1"] interface mozContact{ attribute DOMStringid; readonlyattribute Date? published; readonlyattribute Date? updated; attribute Date? bday; attribute Date? anniversary; attribute DOMString? sex; attribute DOMString? genderIdentity;
  21. 21. [Cached, Pure] attribute sequence<Blob>? photo; [Cached, Pure] attribute sequence<ContactAddress>? adr; [Cached, Pure] attribute sequence<ContactField>? email; [Cached, Pure] attribute sequence<ContactField>? url; [Cached, Pure] attribute sequence<ContactField>? impp; [Cached, Pure] attribute sequence<ContactTelField>? tel;
  22. 22. [Cached, Pure] attribute sequence<DOMString>? name; [Cached, Pure] attribute sequence<DOMString>? honorificPrefix; [Cached, Pure] attribute sequence<DOMString>? givenName; [Cached, Pure] attribute sequence<DOMString>? phoneticGivenName; [Cached, Pure] attribute sequence<DOMString>? additionalName; [Cached, Pure] attribute sequence<DOMString>? familyName; [Cached, Pure] attribute sequence<DOMString>? phoneticFamilyName; [Cached, Pure] attribute sequence<DOMString>? honorificSuffix; [Cached, Pure] attribute sequence<DOMString>? nickname; [Cached, Pure] attribute sequence<DOMString>? category; [Cached, Pure] attribute sequence<DOMString>? org; [Cached, Pure] attribute sequence<DOMString>? jobTitle; [Cached, Pure] attribute sequence<DOMString>? note; [Cached, Pure] attribute sequence<DOMString>? key;
  23. 23. void init(optional ContactPropertiesproperties); [ChromeOnly] void setMetadata(DOMStringid, Date? published, Date? updated); jsonifier; };
  24. 24. •メンバが多くておぢさんびっくりなんじゃよ。。。 •プロパティ全部説明するの大変なのでMDNペタリ –https://developer.mozilla.org/en-US/docs/Web/API/mozContact•ざっくり言うと名前とか読み仮名とか電番とかメアドとかURLとか まあもろもろの配列が持てます •性別とは別にセクシャルアイデンティティが設定できて地味に細や かで面白いですね •idがreadonlyではないのは既存の連絡先を更新する際に使うからで す –既存のIDを設定したmozContactオブジェクトを保存すると置き換えら れます
  25. 25. ### 連絡先の保存まとめ •連絡先の保存はnavigator.mozContacts.save()で行います –mozContacts.save()の引数はmozContactオブジェクトです –mozContacts.save()の返り値はDOMRequestオブジェクトです •mozContactオブジェクトプロパティ多い。。。 –webidl見慣れてない人はMDNの以下のページを参照してください –https://developer.mozilla.org/en- US/docs/Mozilla/WebIDL_bindings–webidlは変更多いので英語版をこまめに追いかけたほうがいいです (翻訳サボってサーセンw)
  26. 26. ## 連絡先の検索 •次は連絡先の検索を見てみます •連絡先を探すのに使えるメソッドは二つあるのでそれぞ れ見ていきます
  27. 27. •まずは条件を指定する場合を見ていきます •B2G/gaia/apps/communications/contacts/js/views/list.jsvargetContactById= function(contactID, successCb, errorCb) { (snip) varoptions = { filterBy: ['id'], filterOp: 'equals', filterValue: contactID}; varrequest = navigator.mozContacts.find(options); request.onsuccess= function findCallback(e) { varresult = e.target.result[0]; if (!fb.isFbContact(result)) { successCb(result); return; } varfbContact= new fb.Contact(result); varfbReq= fbContact.getData(); fbReq.onsuccess= function() { successCb(result, fbReq.result); }; fbReq.onerror= successCb.bind(null, result); }; // request.onsuccessif (typeoferrorCb=== 'function') { request.onerror= errorCb; } }; ### 検索API
  28. 28. ### 検索APIの呼び出し •肝心なところだけ見ましょう •B2G/gaia/apps/communications/contacts/js/views/list.jsvaroptions = { filterBy: ['id'], filterOp: 'equals', filterValue: contactID}; varrequest = navigator.mozContacts.find(options); request.onsuccess= function findCallback(e) { : (snip) : }; // request.onsuccessif (typeoferrorCb=== 'function') { request.onerror= errorCb; } •mozContacts.saveでも見覚えある形ですね •mozContacts.findもDOMRequestを返します
  29. 29. ### 全件取得API•すべての連絡先を取得するAPIを見てみましょう •B2G/gaia/apps/communications/contacts/js/views/list.jsinitConfiguration(function onInitConfiguration() { varsortBy= (orderByLastName=== true ? 'familyName' : 'givenName'); varoptions = { sortBy: sortBy, sortOrder: 'ascending‘ }; varcursor = navigator.mozContacts.getAll(options); (snip) varcontact = evt.target.result; if (contact) { (snip) cursor.continue(); (snip) } }; cursor.onerror= errorCb; });
  30. 30. ### 全件取得APIの呼び出し •全件取得のAPIを使っているのはここです varcursor = navigator.mozContacts.getAll(options); : (snip) : cursor.onsuccess= function onsuccess(evt) { : (snip) : varcontact = evt.target.result; if (contact) { : (snip) : cursor.continue(); } else { : (snip) : } }; cursor.onerror= errorCb;
  31. 31. ### 全件取得APIの呼び出し •これまでのAPIと少し違ってDOMCursorを返してます •DOMRequestのようにonsuccessとonerrorを設定しているのに 加えてcontinueメソッドの呼び出しをしているこの形は複数の値を 返すAPIの基本形です –複数の値を返すAPIではDOMCursorやその派生オブジェクトを返すもの がたくさんあります •DOMCursorは複数の値を返すAPIの反復子を表すオブジェクトで す –continueメソッドが呼ばれた上でメソッドを抜けると次のオブジェクト を引数に再度イベントが発行されます –引数のオブジェクトがnullの場合そのイテレーションが終端に達したとい うことです
  32. 32. ### 検索APIの引数 •mozContacts.findとmozContacts.getAllは検索オプションを引数に取ることができます •ただしmozContacts.getAllはソート条件のみ設定可能です •B2G/gecko/dom/webidl/Contacts.webidldictionary ContactFindSortOptions{ DOMStringsortBy; // "givenName" or "familyName“ DOMStringsortOrder= "ascending"; // e.g. "descending“ }; dictionary ContactFindOptions: ContactFindSortOptions{ DOMStringfilterValue; // e.g. "Tom“ DOMStringfilterOp; // e.g. "startsWith“ any filterBy; // e.g. ["givenName", "nickname"] unsigned long filterLimit= 0; };
  33. 33. ### 検索APIのまとめ •絞り込んでの検索はnavigator.mozContacts.find()で行い ます –mozContacts.find()の引数はContactFindOptionsです –mozContacts.find()の返り値はDOMRequestオブジェクトです –DOMRequestオブジェクトのresultはmozContactオブジェクト の配列です •全件取得はnavigator.mozContacts.getAll()で行います –mozContacts.getAll()の引数はContactFindSortOptionsです –mozContacts.getAll()の返り値はDOMCursorオブジェクトです –DOMCursorオブジェクトのresultはmozContactオブジェクトで す
  34. 34. ## 連絡先の削除 •最後に連絡帳の削除を見ましょう
  35. 35. ### 削除API•B2G/gaia/apps/communications/contacts/js/contacts_remover.jsfunction deleteContact(currentID) { varrequest; varoutreq= {onSuccess: null, onError: null}; varcontact = new mozContact(); contact.id = currentID; if (fbData[contact.id]) { varfbContact= new fb.Contact(fbData[contact.id]); request = fbContact.remove(); } else { request = navigator.mozContacts.remove(contact); } request.onsuccess= function() { outreq.onSuccess(); }; request.onerror= function() { outreq.onError(); }; return outreq; }
  36. 36. ### 削除APIの呼び出し •削除APIの呼び出しだけ見ると •B2G/gaia/apps/communications/contacts/js/contacts_remover.jsvarcontact = new mozContact(); contact.id = currentID; if (fbData[contact.id]) { varfbContact= new fb.Contact(fbData[contact.id]); request = fbContact.remove(); } else { request = navigator.mozContacts.remove(contact); } request.onsuccess= function() { outreq.onSuccess(); }; request.onerror= function() { outreq.onError(); }; こんな感じです もう見慣れた形のDOMRequestを返すタイプのAPIでした
  37. 37. ### 削除APIの引数 •mozContacts.removeはmozContactオブジェクトを引数 に取ります •B2G/gaia/apps/communications/contacts/js/contacts_remover.jsvarcontact = new mozContact(); contact.id = currentID; •このやりかたを見るにIDだけあればいいようです
  38. 38. ### 削除APIのまとめ •削除はnavigator.mozContacts.remove()で行います –mozContacts.remove()の引数はmozContactです –mozContacts.remove()の返り値はDOMRequestです
  39. 39. # さいごに •ちょっと予定と違って中身の説明ができませんでしたが blogかどこかの勉強会でやるのでこうご期待 •といってもContacts APIの実装は素直なのでほかのAPI も一緒にやるかも?Notification APIなんかが近い構 造なので一緒にやる可能性高いかも? •なんかこれ聞いてみたいっていうのがあったら質問箱へ どうぞー –http://www.gcg.bz/labo_blog/?page_id=945

×