Riiiverストア内のiiideaの表示とデバイスの関連性について理解する
ここから実際にサンプルアプリを実行させながら、Riiiver SDKの動作とその仕組みを確認してみましょう。この章は次のような節で構成されています。
Riiiverにログインする
サンプルアプリで一番最初にする処理はRiiiver環境にログインするためのログイン画面を出すことです。Riiiver SDKはRiiiverにログインするために必要な表示機能やセッション管理機能を肩代わりしてくれます。サンプルアプリの動作を確認してどのようにログイン機能を実現しているのか確認してみましょう。
iiideaを実行するにも、新しくiiideaを入手するためにRiiiverストアにアクセスするにも、ユーザーはRiiiver環境にログインすることが必要です。この節ではサンプルアプリで実装している以下の内容を説明します:
- ログインページを表示するWebViewを準備する
 - 準備したWebViewをSDKに渡す
 - ログイン後の処理
 
SDKの初期化
Android版のSDKではアプリのプロセス生成時にSDK初期化用のAPIを呼ぶ必要があります。
iOS版のSDKでは不要ですので次の節(ログインページは外部ブラウザで表示)まで読み飛ばしてください。
最初に呼ばれるMainActivity.ktを確認してみましょう。
iOS版のSDKでは不要ですので読み飛ばしてください。MainActivity.ktclass MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Timber.plant(DebugTree())
        setContentView(R.layout.activity_main)
        RiiiverSDKManager.initialize(applicationContext) { isLoggedIn: Boolean ->
            if (Intent.ACTION_VIEW == intent.action) {
                ...
            } else {
                if (!isLoggedIn) {
                    // 未認証の場合はログイン画面を起動
                    startWebLogin()
                } else {
                    // 強制ダウンロード対象のiiideaを設定
                    RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
                        // 既に認証済みの場合は次の画面へ - If the user have already authenticated, goto next ViewController.
                        transitionFragment(IiideaListFragment())
                    }
                }
            }
        }
    }
    ...
}
RiiiverSDKManager.initialize(applicationContext)が該当箇所です。
初期化後は外部ブラウザからWebトークン情報をSDKに登録する必要があります。Intent.ACTION_VIEWを参照し、外部ブラウザから戻ってきた状態かどうか確認しています。ここではまだ外部ブラウザを開いてすらいないので、このif文では偽の処理が実行されます。次にisLoggedInというプロパティを参照し、既にユーザーが認証されているかどうかを確認しています。こちらもまだ実行したばかりなので、ユーザー認証されているはずがありません。このプロパティからはfalseが返るので、このif文は真の処理が実行されることになります。
つまり、実行したばかりの場合は必ずstartWebLoginへ遷移することになります。
ログインページは外部ブラウザで表示
RiiiverへログインするためのLogin UIとなる画面コンテンツはSDK側で外部ログイン画面として開きます。
ホストアプリはSDKがログイン画面を出す表示先となるURIを指定する必要があります。
サンプルアプリではSDKに伝えるWebLogin画面を起動直後に表示するようにできています。
該当の処理を確認してみましょう。
iOS版はViewController.swift、Android版はMainActivity.ktが該当のファイルです。
 class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        if (RiiiverSDKManager.shared.authenticated == false ){
            // Web認証画面表示  -  Display the webview for the authentication.
            RiiiverSDKManager.shared.startWebLogin { url, error in
                if let error = error {
                    print("\(error)")
                    return
                }
                if let url = url {
                    // ログイン画面を起動
                    self.present(SFSafariViewController(url: url), animated: false, completion: nil)
                }
            }
        }
        else {
            // 既に認証済みの場合は次の画面へ - If the user have already authenticated, goto next ViewController.
            nextViewController()
        }
    }
    ...fun startWebLogin() {
    // Web認証画面表示  -  Display the webview for the authentication.
    RiiiverSDKManager.startWebLogin(object : IERAuthWebLoginCallback {
        override fun openUrl(uri: Uri?) {
            Timber.d("openUrl in")
            val intent = Intent(Intent.ACTION_VIEW, uri)
            startActivity(intent)
        }
        override fun onError(error: Exception?) {
            if(error != null) {
                Timber.e("onError in: error %s", error.message)
            }
        }
    })
}
ここではRiiiverSDKManagerの機能をコールしていることがわかります。
iOS版ではauthenticatedというプロパティを参照し既にユーザーが認証されているかどうかを確認しています。もちろんまだ実行したばかりなので、ユーザー認証されているはずがありません。このプロパティからはfalseが返るので、このif文は真の処理側が実行されることになります。
Android版ではSDKの初期化時にisLoggedInというプロパティを確認して同様の判断処理を既に行っています。
このサンプルアプリではSDKから得られる情報などを管理するためにRiiiverSDKManagerというクラスを利用する形をとっています。
該当の処理の一部抜粋を確認してみましょう。
iOS版はRiiiverSDKManager.swift、Android版はRiiiverSDKManager.ktが該当します。
class RiiiverSDKManager : ERSDKDelegate {
    
    /// Singleton
    static let shared = RiiiverSDKManager()
    
    /// accecss Token  -  認証トークン
    public private(set) var accessToken: String?
    
    /// ID Token
    public private(set) var idToken: String?
    
    private init() {
        ERSDK.sharedInstance.delegate = self
    }
    
    /// 認証済みかどうか (true:認証済み、false:未認証)
    /// Is this user authenticated?  true:  Yes,  false: No
    public var authenticated: Bool {
        return ERAuth.sharedInstance.isLoggedIn()
    }
    
    /// RiiiverSDKからWeb認証画面表示する
    ///  set a web view to be  invoked by Riiiver SDK for the web page authentication.
    /// - Parameters:
    ///   - completion:
    func startWebLogin(completion:((URL?, Error?)->Void)?) {
        let deviceId:[String] = AppManager.shared.getDeviceId()
        // Display the authentication web page.  -  Web認証画面表示
        ERAuth.sharedInstance.startWebLogin(deviceIds: deviceId, completion: completion)
    }
    ....RiiiverSDKManager.shared.メソッド名object RiiiverSDKManager : ERSDKDelegate {
    private var erSdk: ERSDK? = null
    private var accessToken: String? = null
    private var idToken: String? = null
    /** 認証済みかどうか (true:認証済み、false:未認証)
     *  Is this user authenticated?  true:  Yes,  false: No
     */    val authenticated: Boolean
        get() {
            return ERAuth.getInstance().isLoggedIn
        }
    /**
     *  RiiiverSDKを初期化する
     *  @param context Activityのコンテキスト
     *  @param complete 認証済みかどうか (true:認証済み、false:未認証)
     */    fun initialize(context: Context, complete: (isLoggedIn: Boolean) -> Unit) {
        Timber.i("initialize")
        if (erSdk != null) {
            // initialize 完了済み
            Timber.d("Initialize has already been completed")
            complete(authenticated)
            return
        }
        // ERAuthの初期化
        ERAuth.getInstance().initialize(context)
        erSdk = ERSDK.Builder.with(context)
            .includeBlockExecutorPackageName(pieceCorePackageName).build()
        // iiideaの実行状態を監視
        erSdk!!.setDelegate(this)
        // Preference関連の初期化
        IiideaSettingFragment.initialize(context)
        complete(authenticated)
    }
    ....
}RiiiverSDKManager.メソッド名
SDKに渡すWebLoginの説明に戻りましょう。(iOS版はViewController.swift、Android版はMainActivity.ktのコード部分です)
サンプルアプリを起動するとすぐに、RiiiverSDKManagerクラスのstartWebLogin関数を呼んでいます。
RiiiverSDKManager.shared.startWebLogin { url, error in
    if let error = error {
        print("\(error)")
        return
    }
    if let url = url {
        // ログイン画面を起動
        self.present(SFSafariViewController(url: url), animated: false, completion: nil)
    }
}RiiiverSDKManager.startWebLogin(object : IERAuthWebLoginCallback {
    override fun openUrl(uri: Uri?) {
        Timber.d("openUrl in")
        val intent = Intent(Intent.ACTION_VIEW, uri)
        startActivity(intent)
    }
    override fun onError(error: Exception?) {
        if(error != null) {
            Timber.e("onError in: error %s", error.message)
        }
    }
})
startWebLogin関数内にてSDKにWebView表示を任せる際、Riiiverにログインするために必要な以下の情報を合わせて渡しています:
- vendorId - ベンダーID。
 - deviceId - デバイスID。
 - appName - アプリの名前。
 
この処理で先程皆さんがアプリの設定ファイルerconfiguration.jsonとAppManager.swiftで記述した情報をログイン時にRiiiverサーバーに渡していることになります。Riiiverにはこのサンプルアプリが渡す情報が既に登録されているので、このサンプルプログラムも無事にログインできるのです。
これらのRiiiverSDKのログイン関連の処理はERSDKLoginクラス内で定義されています。これらのファイルには手を入れる必要はありません。そのままで動作するようになっていますので、今はそのままでご利用下さい。
Note: RiiiverSDKを利用しているとERという言葉を見かけることがあります。これはRiiiverの前身となるProjectの名前です。RiiiverSDK内の名前で各所に出てきますのでRiiiverだと思って読み替えてください!(SDK内に登場する名前と、現在の呼び名の対応表はこちら)
ここまで説明してきたところまでが無事に動作すると、以下のように外部ブラウザでログイン画面が表示されるはずです。

無事に表示されましたか?
Riiiverへログインするアカウントをお持ちでない場合はこのサンプル画面のからユーザー登録もすることが出来ます。アカウントを生成して実際にログインできるか確認してみて下さい。
GoogleアカウントやFacebookアカウント、Apple IDを利用したログインもできます。
この画面にユーザーがログインもしくは新たにサインアップして、認証処理が終了した時にブラウザからアプリ画面に戻ります。
認証処理が終了したタイミングで、以下の処理が呼ばれます。
ログイン画面は外部ブラウザで表示されています。ログインに成功するとブラウザからサンプルアプリの方にURLスキーマでアプリ間で遷移が起きます。ブラウザからsampleアプリに遷移すると、`AppDelegate.swift`の`func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : **Any**] = [:]) -> Bool ` 関数が呼ばれます。func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        let sourceApplication = options.keys.contains(UIApplication.OpenURLOptionsKey.sourceApplication) ? options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String : ""
        // Riiiverログイン画面からのWebトークン情報が含まれているかどうか判断する
        if (ERAuth.sharedInstance.interceptApplication(app, open: url, sourceApplication: sourceApplication, annotation: "") == true) {
            if let vc = self.window?.rootViewController as? ViewController {
                // Webトークンを取得できた場合、トークン情報をSDKに保存する
                vc.challengeAuthByWebLogin()
            }
        }
        return true
    }/// RiiiverSDKにWebLogin情報を設定する
func challengeAuthByWebLogin() {
    RiiiverSDKManager.shared.challengeAuthByWebLogin() { error, authToken in
        if(error != nil){
            print("error. \(String(describing: error))")
        }
        self.nextViewController()
    }
}class MainActivity : AppCompatActivity(){
...
    override fun onCreate(savedInstanceState: Bundle?) {
    ...
        RiiiverSDKManager.initialize(applicationContext) { isLoggedIn: Boolean ->
            if (Intent.ACTION_VIEW == intent.action) {
                // ブラウザからWebトークン情報をSDKに登録する
                RiiiverSDKManager.challengeAuthByWebLogin(intent!!, object :
                    IERAuthChallengeCallback {
                    override fun onSuccess(authToken: ERAuthToken?) {
                        Timber.d("onSuccess in")
                        // 強制ダウンロード対象のiiideaを設定
                        RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
                            // Go to next View - 次の画面へ
                            transitionFragment(IiideaListFragment())
                        }
                    }
                    override fun onError(error: Exception) {
                        Timber.e("onError in: error %s", error.message)
                    }
                })
            } 
         ...
        }
    ...
    }
...
}
iOS版では ViewController.swift のnextViewController関数が呼ばれ、強制ダウンロード対象のiiideaを設定し、ログインしたユーザーがダウンロードしているiiideaを取得して表示する画面(SampleViewController)に遷移しています。
Android版ではMainActivity.kt のforcedDownloadApplet関数が呼ばれ、同じく強制ダウンロード対象のiiideaを設定し、ログインしたユーザーがダウンロードしているiiideaを取得して表示する画面(IiideaListFragment)に遷移しています。
(下記、その部分抜粋、Androidは上と同じ)
class ViewController: UIViewController {
...
    func nextViewController() {
        // 強制ダウンロード対象のiiideaを設定
        RiiiverSDKManager.shared.forcedDownloadApplet() {isSuccess,error in
            self.performSegue(withIdentifier: "toSample", sender: self)
        }
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let sampleViewController = segue.destination as? SampleViewController {
            sampleViewController.isReload = true
        }
    }
}class MainActivity : AppCompatActivity(){
...
    override fun onCreate(savedInstanceState: Bundle?) {
    ...
        RiiiverSDKManager.initialize(applicationContext) { isLoggedIn: Boolean ->
            if (Intent.ACTION_VIEW == intent.action) {
                // ブラウザからWebトークン情報をSDKに登録する
                RiiiverSDKManager.challengeAuthByWebLogin(intent!!, object :
                    IERAuthChallengeCallback {
                    override fun onSuccess(authToken: ERAuthToken?) {
                        Timber.d("onSuccess in")
                        // 強制ダウンロード対象のiiideaを設定
                        RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
                            // Go to next View - 次の画面へ
                            transitionFragment(IiideaListFragment())
                        }
                    }
                    override fun onError(error: Exception) {
                        Timber.e("onError in: error %s", error.message)
                    }
                })
            } 
         ...
        }
    ...
    }
...
}
iiideaのリストを表示する画面ではRiiiverSDKのgetMyAppletsというAPIを使用してユーザーがダウンロードしているiiidea情報の一覧を取得しています。
(下記、その部分抜粋)
   class SampleViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
...
    override func viewWillAppear(_ animated: Bool) {
        if (isReload == true) {
            indicator.startAnimating()
            // RiiiverSDKからiiidea一覧を取得   -   Get an iiidea list from RiiiverSDK
            RiiiverSDKManager.shared.getMyApplets(completion: { (isSuccess, iiideas, error) in
                self.indicator.stopAnimating()
                if (isSuccess == false) {
                    print("getMyApplets failed")
                    // 失敗した場合であってもiiide実行サンプル画面へ(何もできなくなるので)
                    // Even if we got errors, keep going to the iiidea executer pane.
                }
                self.iiideas = iiideas
                self.tableView.reloadData()
            })
        }
        ...
    }
    ...
}class IiideaListFragment : Fragment() {
...
        RiiiverSDKManager.getMyApplets { iiideaList: MutableList<ERApplet>?, _: Exception? ->
            if (iiideaList == null || progress_bar == null) {
                return@getMyApplets
            }
            progress_bar.visibility = ProgressBar.INVISIBLE
            val iiideas = iiideaList.toList()
            // ListViewをセット
            val adapter = AppletArrayAdapter(requireContext(), R.layout.fragment_iiidea_list, iiideas)
            val listView: ListView = view.findViewById<View>(R.id.list_view) as ListView
            listView.adapter = adapter
            // セルを選択されたら詳細画面フラグメント呼び出す
            listView.onItemClickListener = OnItemClickListener { _, _, position, _ ->
                goToInfoFragment(iiideas[position])
            }
        }
...
ここまで、読み取れたら一度、サンプルアプリを実行して実際にログインしてみましょう。
実際にユーザー登録後にログインが成功したら、実装通り、iiideaのリストを表示する画面に遷移するはずです。
(ログインしたユーザーがiiideaを一切入手していない場合は何もiiideaは表示されません。)
getMyAppletsのAppletという言葉はiiideaという名前がつく前の呼び方です。RiiiverSDK内でも何回か登場しますので、適宜、読み替えてください。(SDK内に登場する名前と、現在の呼び名の対応表はこちら)
2回目以降のRiiiver Platformへの自動ログインについて
一度SDKを通じてログインするとSDK側はスマートフォンのフラッシュ領域に認証情報を記憶するので、次回以降はユーザーに入力を求めることなく、Riiiver環境に自動ログインすることができます。
アプリとして実装しなければならないのは、アプリが立ち上がった時にSDKに対して、すでに認証情報を持っているかどうかを問い合わせることです。
該当部分を見てみましょう。
iOS版はViewController.swift、Android版はMainActivity.ktが該当するファイルです。
...
override func viewWillAppear(_ animated: Bool) {
    if (RiiiverSDKManager.shared.authenticated == false ){
        ...
    }
    else {
        // 既に認証済みの場合は次の画面へ - If the user have already authenticated, goto next ViewController.
        nextViewController()
    }
}
...class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        RiiiverSDKManager.initialize(applicationContext) { isLoggedIn: Boolean ->
            if (Intent.ACTION_VIEW == intent.action) {
                ...
            } else {
                if (!isLoggedIn) {
                    // 未認証の場合はログイン画面を起動
                    startWebLogin()
                } else {
                    // 強制ダウンロード対象のiiideaを設定
                    RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
                        // 既に認証済みの場合は次の画面へ - If the user have already authenticated, goto next ViewController.
                        transitionFragment(IiideaListFragment())
                    }
                }
            }
        }
    }
...
}
iOS版ではauthenticatedというプロパティを参照し既にユーザーが認証されているかどうかを確認しています。Android版ではSDKの初期化時にisLoggedInというプロパティを確認して同様の判断処理を既に行っています。
既に認証済みの場合、このif文は偽の処理側が実行されることになります。
サンプルアプリではこのような実装をすることで、まだRiiiverにログインしていないユーザーにはログイン画面を表示し、すでにログイン済の場合はログイン後のViewを表示する様に実装しています。
Riiiverストアを表示する
実際にiPhone/Androidの実機を利用してデバッグしてログイン動作の確認をしてみましょう。(現在、SDKは実機での実行のみをサポートしております。)
デバッグを開始し、ログイン画面が表示されたら、登録したEmailとパスワードを入力してRiiiverにログインして下さい。ログインが成功したら次の様な画面になるはずです。

まだログインしただけなので画面が空っぽです。この画面はユーザーがダウンロードしたiiideaのリストが表示されるの画面です。
iiideaをダウンロードするには、ユーザーがWeb上のRiiiverストアに行って、欲しいiiideaをダウンロードする必要があります。サンプルアプリでは右上のStoreボタンを押すことで、WebViewを表示し、Riiiverストアを表示するように実装しています。実際にタップして動作を確認してみて下さい。
ストアはユーザーにカスタマイズされた動的なコンテンツを表示するように実装されています。このストア画面もSDK側がユーザー認証情報を管理しているので、SDKに準備したWebViewを渡すだけでストアの表示が完結します。ただ、WebView(ストア画面)内には、ストアから「ダウンロードしたiiideaリスト画面」に戻る動線がありません。そのため、ストア画面から画面を戻すにはネイティブ側でリスト画面に戻るボタンを用意しています。「Store」のボタンをタップすると、以下の様な画面が表示されるはずです。

↑の画面の黒い上のペインにある「Back to the iiidea list」というボタンはサンプルアプリで実装しているボタン、黒い部分より下にあるペインはRiiiverストアのWebView部分です。
WebView部分をしたにスクロールしていくと、新着のiiideaというセクションがあります。

この図の様に「サンプルiiidea」が見えればいいのですが、残念ながらまだダウンロードできるiiideaはひとつもありません。実際に実行されたストア画面には何もiiideaが表示されていないはずです。それは皆さんのVendorID、DeviceIDで利用できるiiideaがストア上に存在していないからです。
ここでストアに表示されるiiidea、そのiiideaに含まれるPiece、そしてVendorIDとAppName、DeviceIDの関係について説明します。
ストアに渡す情報とデバイスに対応するiiideaの表示
サンプルアプリがストアを表示するとき、RiiiverSDKのどの関数を呼んでいるか見てみましょう。
iOS版はRiiiverSDKManager.swift、Android版はRiiiverSDKManager.ktが該当するファイルです。
    func openStore(webView: WKWebView, delegate: ERAuthStoreWebViewDelegate) {
        let deviceId:[String] = AppManager.shared.getDeviceId()
        ERAuth.sharedInstance.openStore(webView: webView, deviceIds: deviceId, delegate: delegate)
    }
}/**
*  RiiiverSDKからiiideaStore画面表示する
*  Display Riiiver Store page via Riiiver SDK.
*/fun openStore(webView: WebView, delegate: IERAuthStoreWebViewDelegate) {
    // SDKの問題で一時的にcookieを削除する必要がある(SDKが対処された後は削除予定)
    val cookieManager: CookieManager = CookieManager.getInstance()
    cookieManager.removeAllCookies(null)
    webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
    val deviceIds = getDeviceIdList()
    ERAuth.getInstance().openStore(webView, deviceIds, delegate)
}
RiiiverSDKには、準備したwebView, 登録時に払い出されたVendorID, DeviceID, 登録したAppNameを渡しています。(veodorTokenは通常利用しませんのでnilを渡して下さい。)ここで行われている内容を図示したものを示します。
例として、上の図のアプリはDevice AとDevice Bの2つのデバイスを管理できるアプリだとします。このアプリがストアに訪れるときには、ストアから入手したいiiideaはDevice AとDevice Bで利用できるものに絞りたいはずです。(Device AやBで扱えないiiideaが表示されると困りますよね。)
図のようにストアを表示する際に、Vendor IDとDevice IDを渡すことで、実際に渡したデバイスで利用することができるiiideaのみを表示するようにフィルタリングができます。
今、みなさんのサンプルアプリからストアにiiideaを表示されるには、皆さんが登録したデバイスで扱えるiiideaをストアにリリースする必要があります。晴れてリリースできたら、ストアからそのiiideaダウンロードして、サンプルアプリの動作を確認することができます。
まずは、みなさんが登録したデバイスで動作するiiidea作ることにしましょう。
ここで注目すべきなのは、一つのiiideaがどのデバイスで扱えるのか?という判断はどこでされているか?ということです。次の節では、iiideaとPieceと対応デバイスの関連性について説明します。
iiideaとPieceの関連性と対応デバイス
あるデバイスがあるiiideaを扱えるかどうか?という対応関係は、そのiiideaに含まれいるPieceがそのデバイスで扱えるかどうかで決まります。
上の図を見て下さい。デバイスA専用のPieceと、デバイスに依存していないPieceで構成されている上の行のiiideaは、デバイスAで扱うことができます。反対に、デバイスA以外のデバイスに依存しているPieceはデバイスAでは取り扱うことが出来ないため、下段の行のiiideaはデバイスAでは扱えないiiideaと判断されます。
Pieceがデバイスに依存しているかどうか、またベンダーに依存しているかどうか?という情報はPieceJSONで宣言されます。このドキュメントでPieceJSONの仕様について記載をしていますが、そのドキュメントでは「デバイス」と言う概念を説明していませんでした。(RiiiverSDKを利用する開発者にのみ関係するため外しています)そのため、デバイスとベンダー依存の概念も説明できていません。ここではPieceJSONでデバイスとベンダーに依存している宣言をどの様に記載するのか説明します。
下記のPieceJSONの例のように、deviceId, vendorIdというキーで、IDを記載できる項目があります。
{
  "title": {
    "en": "Current Temperature (celsius)",
    "ja": "現在の気温 (摂氏)"
  },
  "version": "1.0.0",
  "sdkVersion": "1.0.0",
  "deviceId": "none",
  "vendorId": "none",
  "description": {
    "en": "~~What is this Piece?~~\nGet the current temperature in degrees Celsius (°C).\n\n~~How do I use it?~~\nInclude this Piece in an iiidea to output a simple number representing the current temperature in °C.\nYou can choose in the iiidea settings for where to get information.\n\n~~Notes~~\nThe output value will be -50 if this Piece cannot get information due to network or a separate error.",
    "ja": "【どんなPiece?】\n現在の気温を摂氏で次のPieceに渡します。\n\n【どうやって使うの?】\n「地域」のドラムロールから、気温を知りたい場所を選択してください。\n\n【ご注意!】\n気温をうまく取得できなかった場合は値が -50 となります。"
...上記の例では、deviceId, vendorId共に"none"となっています。「none」とはデバイスへの依存がないことを表しています。つまり、この例のPieceはどのデバイスでも扱うことができるということです。
次に、デバイスとベンダーに依存しているPieceの例を示します。
{
  "title": {
    "en": "samplePiece",
    "ja": "サンプルPiece"
  },
  "version": "1.0.0",
  "sdkVersion": "1.0.0",
  "deviceId": "5db923ec51e157128cdef4ea_mTO8FZ4T",
  "vendorId": "ghzY5db923ec51e157128cdef4eaPUUr",
  "description": {
    "en": "~~What is this Piece?~~\nAction Piece Sample.\n\n~~How do I use it?~~\nPiece for testing with the sample app.",
    "ja": "【どんなPiece?】\nアクションPieceサンプル\n\n【どうやって使うの?】\nサンプルアプリでの動作確認用Piece"
  },
...上記の例のPieceは、デバイスIDが"5db923ec51e157128cdef4ea_mTO8FZ4T"、ベンダーIDが"ghzY5db923ec51e157128cdef4eaPUUr"とerconfiguration.jsonとAppManager.swiftで定義しているアプリからのみ利用可能なPieceであることを宣言しています。
例えば、あなたのVendorIDのみを宣言し、DeviceIDを"none"とするとあなたの組織のアプリからはデバイスに関係なく利用できるPieceとして宣言することができます。
今みなさんがビルドしてデバッグしようとしているサンプルアプリで扱えるiiideaを作るには、みなさんが登録したVendorID/DeviceIDで扱えるPieceを作成し、そのPieceで構成すればよいことになります。
実際にサンプルアプリで扱えるiiideaを作成する前に、次の節ではPieceを開発中のフェーズで公開することなしにデバッグができるのか?と言った、公開前のPiece、iiideaの扱いについて説明します。
開発時のiiideaとPieceの扱いについて
iiideaはRiiiverAppを使って、3つのPieceを選ぶだけで(コーディングなしで)作成することができます。
実際のRiiiverAppでの作成方法については、こちらのドキュメントを参考にして下さい。
RiiiverAppを利用してiiideaを作るときに見えているPieceは通常公開されているものです。皆さんのようにPieceを開発する際にPieceがどの様なプロセスを取って公開されるのかを下図に示します。
皆さんは次の章で自前のPieceを開発し、Riiiver上にPieceをアップロードします。このとき、皆さんはPieceBuilderというWebポータルツールを利用して作成したPieceをアップロードします。
皆さんが開発したPieceはRiiiverにアップロード後、「テスト中」という状態になります。
テスト中
「テスト中」という状態は、みなさんがまだPieceを評価している最中、という状態です。この状態では未だPieceは公開されておらず、開発者と、企業登録時にテスター登録したアカウントの人以外の人はこのPieceの存在を知ることはありません。テスト中の段階で、開発者である皆さんは開発者アカウントであるemailアドレスを利用してRiiiverAppでRiiiverにログインすると、テスト中状態のPieceがすべて見え、実際にテスト中のPieceを組み合わせてiiideaを作成することができます。
テスト中にバグを見つけて、修正版の準備ができたら、PieceBuilder上の対象のPieceの編集画面から、もう一度PieceのコードやJSONファイルをアップロードして、Pieceをアップデートすることが出来ます。この状態で沢山デバッグしましょう。
十分にデバッグし、Pieceを公開したい場合には、PieceBuilderを利用して対象のPieceを提出することができます。提出されたPieceはRiiiverの事務局側で審査します。提出されたPieceは「審査結果待ち」という状態に遷移します。
審査結果待ち
「審査結果待ち」という状態は、基本的にはテスト中の状態と同じです。Riiiver事務局が審査の結果を出すには通常1-5営業日程かかります。審査の結果をお待ち下さい。結果は登録したメールアドレスに報告されます。
審査の結果、晴れて承認された場合には、皆さんのPieceは審査OKとなり「公開」されます。
公開 (審査OK)
「公開」という状態は、誰もがRiiverAppを通じて、作成時にそのPieceを見ることが出来、選んでiiideaの材料にすることができる状態です。
取り下げ (審査NG)
残念ながら、審査の結果承認されなかったPieceは「取り下げ (審査NG)」状態になります。この状態は基本的にはテスト中と同じ状況で、関係者にしかPieceは見えていません。問題を解決して再度PieceJSON、PieceCoreをアップロードしてください。
一度、公開されているPieceも、あとから問題が発覚した場合に公開を取り下げることがあります。その場合にも、Pieceは「取り下げ (審査NG)」状態になります。一度公開されたものが、取り下げ状態になった場合、公開時にダウンロードしたユーザーには、取り下げられたPieceを含む全てのiiideaの説明文章に使えなくなった旨のメーセージが記述され、対象アイデアが利用できなくなります。RiiiverAppからも見えなくなります。
以上で、開発フェーズにおけるPieceの公開プロセスの説明は終わりです。次の章「自分のオリジナルPieceを作る」からは、実際にみなさん自身のiiideaを作っていきましょう。