Understanding iiidea displays and device associations in the iiidea Store
Now, check how Riiiver SDK works while actually running the sample app. This chapter consists of the following sections.
Login to Riiiver
The first thing to do in the sample app is to display a login screen to log in to the Riiiver environment. Riiiver SDK takes care of the display and session management functions required to log in to Riiiver. Check how the sample app works and see how the login function is achieved.
To run iiidea or to access the iiidea Store to obtain new iiidea, users must log in to the Riiiver environment. This section describes the following items implemented in the sample app:
- Prepare WebView to display login screen
- Hand over the prepared WebView to SDK
- Process after the login
Initialize SDK
For the Android version of SDK, it is necessary to call an initialization API when generating the application process.
For the iOS version of SDK, it is not necessary. Please skip to the next section "Display login screen via an external browser".
Check MainActivity.kt
which will be called first.
class 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) {
// If not authenticated, start the login screen
startWebLogin()
} else {
// select force download iiidea
RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
// If the user have already authenticated, goto next ViewController.
transitionFragment(IiideaListFragment())
}
}
}
}
}
...
}
RiiiverSDKManager.initialize(applicationContext)
is the relevant part.
After initialization, the Web token information must be registered to SDK via an external browser. Referring to Intent.ACTION_VIEW
. it checks to see if it is in the status returned from the external browser. Since the external browser is not even opened yet here, false processing will be executed with this if statement. Next, referring to the property called isLoggedIn
, it checks if the user has already been authenticated. Since this has just been executed, the user could not have been authenticated. Since this property returns false, true processing will be executed with this if statement.
In other words, when it is just executed, it will always transition to startWebLogin.
Display login screen via an external browser
The screen content that serves as the Login UI to enable login to Riiiver will be opened as an external login screen on the SDK side.
The host application needs to specify the URL to which the SDK will display the login screen.
The sample app is designed to display the WebLogin screen that communicates to the SDK immediately after startup.
Review the relevant process here.
ViewController.swift
for iOS, MainActivity.kt
for Android, is the relevant file.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
if (RiiiverSDKManager.shared.authenticated == false ){
// Display the webview for the authentication.
RiiiverSDKManager.shared.startWebLogin { url, error in
if let error = error {
print("\(error)")
return
}
if let url = url {
// Launch login screen
self.present(SFSafariViewController(url: url), animated: false, completion: nil)
}
}
}
else {
// If the user have already authenticated, goto next ViewController.
nextViewController()
}
}
...
fun startWebLogin() {
// 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)
}
}
})
}
Here you can see that the RiiiverSDKManager function is being called.
In the iOS version, it checks if the user has already been authenticated by referring to the property authenticated
. Since it has just been executed, of course, the user could not have been authenticated. Since this property returns false, this if statement will result in a true process.
In the Android version, the same decision process is already performed by checking the propertyisLoggedIn
at the time of initializing the SDK.
This sample app is set up to use a class called RiiiverSDKManager to manage information obtained from the SDK.
Review some excerpts from the relevant process here.
RiiiverSDKManager.swift
for iOS, or RiiiverSDKManager.kt
for Android, is the relevant file.
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
}
/// Is this user authenticated? true: Yes, false: No
public var authenticated: Bool {
return ERAuth.sharedInstance.isLoggedIn()
}
/// 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.
ERAuth.sharedInstance.startWebLogin(deviceIds: deviceId, completion: completion)
}
....
object RiiiverSDKManager : ERSDKDelegate {
private var erSdk: ERSDK? = null
private var accessToken: String? = null
private var idToken: String? = null
/**
* Is this user authenticated? true: Yes, false: No
*/ val authenticated: Boolean
get() {
return ERAuth.getInstance().isLoggedIn
}
/**
* Initialize 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
}
// Initialize ERAuth
ERAuth.getInstance().initialize(context)
erSdk = ERSDK.Builder.with(context)
.includeBlockExecutorPackageName(pieceCorePackageName).build()
// Monitor the execution status of iiidea
erSdk!!.setDelegate(this)
// Initialize Preference
IiideaSettingFragment.initialize(context)
complete(authenticated)
}
....
}
Now, go back to the explanation of WebLogin to be passed to the SDK. (It is the code part of ViewController.swift
for iOS, or MainActivity.kt
for Android.)
As soon as the sample app is launched, the startWebLogin
function of the RiiiverSDKManager class is called.
RiiiverSDKManager.shared.startWebLogin { url, error in
if let error = error {
print("\(error)")
return
}
if let url = url {
// Launch login screen
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)
}
}
})
In the startWebLogin
function, the following information required for login to Riiiver is also passed when the SDK takes care of the WebView display:
- vendorId - Vendor ID
- deviceId - Device ID
- appName - Application name
In this process, the information that you have just entered in the application configuration file, erconfiguration.json
and AppManager.swift
is passed to the Riiiver server at login. Since the information that this sample app passes to Riiiver is already registered, this sample program can also log in successfully.
These login-related processes of the RiiiverSDK are defined within the ERSDKLogin
class. No change is required for these files. Since they are designed to work as is, please use them as they are for now.
Note: You may see the term ER when using the Riiiver SDK. This is a former Project name of Riiiver. When it appears as a name in various parts of the RiiiverSDK, just read it as Riiiver! (Click here for a correspondence chart between the names that appear in the SDK and their current names)
If everything described up to this point works successfully, the login screen should appear in an external browser as shown below.
Was it displayed successfully?
If you do not have an account to log in to Riiiver, it is also possible to register as a user from this sample screen. Please create an account and see if you can actually log in.
It is also possible to log in using Google account, Facebook account, or Apple ID.
When a user logs in on this screen or signs up anew and the authentication process is complete, it returns to the application screen from the browser.
The following process is called when the authentication process is completed.
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 : ""
// Determine if the web token information from the Riiiver login screen is included
if (ERAuth.sharedInstance.interceptApplication(app, open: url, sourceApplication: sourceApplication, annotation: "") == true) {
if let vc = self.window?.rootViewController as? ViewController {
// If you can get a web token, save the token information in the SDK
vc.challengeAuthByWebLogin()
}
}
return true
}
/// Set WebLogin information in Riiiver SDK
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) {
// Register the web token information in the SDK from the browser
RiiiverSDKManager.challengeAuthByWebLogin(intent!!, object :
IERAuthChallengeCallback {
override fun onSuccess(authToken: ERAuthToken?) {
Timber.d("onSuccess in")
// Select force download iiidea.
RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
// Go to next View
transitionFragment(IiideaListFragment())
}
}
override fun onError(error: Exception) {
Timber.e("onError in: error %s", error.message)
}
})
}
...
}
...
}
...
}
In the iOS version, it calls the nextViewController
function of ViewController.swift
, sets iiidea for forced downloading, and transitions to the screen (SampleViewController
) to obtain and display the iiidea being downloaded by the logged-in user.
In the Android version, it calls the forcedDownloadApplet
function of MainActivity.kt
, similarly sets iiidea for forced downloading, and transition to the screen (IiideaListFragment
) to obtain and display the iiidea being downloaded by the logged-in user.
(Below is an excerpt from that section, the same as above for Android)
class ViewController: UIViewController {
...
func nextViewController() {
// Select force download 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) {
// Register the web token information in the SDK from the browser
RiiiverSDKManager.challengeAuthByWebLogin(intent!!, object :
IERAuthChallengeCallback {
override fun onSuccess(authToken: ERAuthToken?) {
Timber.d("onSuccess in")
// Select force download iiidea
RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
// Go to next View
transitionFragment(IiideaListFragment())
}
}
override fun onError(error: Exception) {
Timber.e("onError in: error %s", error.message)
}
})
}
...
}
...
}
...
}
For the screen displaying the list of iiidea, it uses getMyApplets
API of the RiiiverSDK to obtain a list of iiidea information being downloaded by the user.
(Below is an excerpt from that section)
class SampleViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
...
override func viewWillAppear(_ animated: Bool) {
if (isReload == true) {
indicator.startAnimating()
// Get an iiidea list from RiiiverSDK
RiiiverSDKManager.shared.getMyApplets(completion: { (isSuccess, iiideas, error) in
self.indicator.stopAnimating()
if (isSuccess == false) {
print("getMyApplets failed")
// 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])
}
}
...
Once you have completed this far, try running the sample app and actually login.
If the login is actually successful after user registration, the screen should transition to display the iiidea list, as implemented.
(If the logged-in user has not obtained any iiidea, no iiidea will be displayed.)
The term Applet in getMyApplets
is a former term before it was named iiidea. When it often appears in the Riiiver SDK, just read it as appropriate. (Click here for a correspondence chart between the names that appear in the SDK and their current names)
Automatic login to Riiiver Platform for the second time and after
Once a user logs in via the SDK, the SDK stores the authentication information in the flash area of the smartphone so that the user can automatically log in to the Riiiver environment without getting asked to enter the information next time.
What needs to be implemented in an application is to query the SDK if it already has the credentials when the application is launched.
Take a look at the relevant section.
ViewController.swift
for iOS, or MainActivity.kt
for Android, is the relevant file.
...
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) {
// If not authenticated, start the login screen
startWebLogin()
} else {
// Select force download iiidea
RiiiverSDKManager.forcedDownloadApplet{ _: Boolean, _: ERError? ->
// If the user have already authenticated, goto next ViewController.
transitionFragment(IiideaListFragment())
}
}
}
}
}
...
}
In the iOS version, it checks if the user has already been authenticated by referring to the property called authenticated
. In the Android version, a similar decision process is already performed by checking the property isLoggedIn
at the time of the SDK initialization.
If already authenticated, the false processing will be executed with this if statement.
The sample app is implemented in such a way that the login screen is displayed to users who have not yet logged in to Riiiver, and the View after login is displayed to users who have already logged in.
Display iiidea Store
Now check the login operation by actually using an actual iPhone/Android device to debug. (Currently, the SDK only supports execution on an actual device.)
When the login screen appears after starting debugging, enter your registered email and password to log in to Riiiver. If the login is successful, you should see the following screen.
Since you have just logged in, the screen is still empty. This screen will display a list of iiidea downloaded by the user.
To download iiidea, users need to go to the Riiiver Store on the web and download the iiidea they want. In the sample app, it is implemented to display WebView and show the Riiiver Store by tapping the Store button in the upper right corner. Please actually tap to confirm the operation.
The Store is implemented to display customized, dynamic content to users. Since the SDK also manages user authentication information for this Store screen, the Store display is completed simply by passing the prepared WebView to the SDK. However, within WebView (the Store screen), there is no route to go back to the "downloaded iiidea list screen" from the Store. Therefore, to return from the Store screen, a button to return to the list screen is provided on the native side of the sample app. When you tap the "Store" button, you should see a screen like the one below.
In the screen above, the "Back to the iiidea list" button in the upper black pane is the button implemented in the sample app, and the pane below the black area is the WebView portion of the Riiiver Store.
If you scroll down the WebView section, you will find a section called “New iiidea”.
It would be nice if you could see "sample iiidea" as shown in this figure, but unfortunately there is no iiidea available for download at this time. The actual executed Store screen should not show any iiidea. It is because the iiidea available for your VendorID and DeviceID do not exist in the Store.
This section describes the iiidea displayed in the Store, the Piece contained in that iiidea, and the relationship between VendorID, AppName, and DeviceID.
Information to be passed to the Store and displaying iiidea for supported devices
Here, you can review which function of RiiiverSDK is called when the sample app displays the Store.
RiiiverSDKManager.swift
for iOS, or RiiiverSDKManager.kt
for Android, is the relevant file.
func openStore(webView: WKWebView, delegate: ERAuthStoreWebViewDelegate) {
let deviceId:[String] = AppManager.shared.getDeviceId()
ERAuth.sharedInstance.openStore(webView: webView, deviceIds: deviceId, delegate: delegate)
}
}
/**
* Display Riiiver Store page via Riiiver SDK.
*/fun openStore(webView: WebView, delegate: IERAuthStoreWebViewDelegate) {
// Cookies need to be removed temporarily due to an SDK issue (will be removed after the SDK is addressed)
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 receives the prepared WebView, VendorID and DeviceID that were issued at the time of registration, and registered AppName. (As vendorToken is usually not used, nil
should be passed.) The diagram below shows what is being done here.
As an example, it assumes that the app in the diagram above is an application that can manage two devices, Device A and Device B. When this app enters the Store, you will expect to see only the iiidea that you want and works with Device A and Device B. (There is no use in displaying iiidea that does not work with Device A or B.)
When displaying the Store as shown in the diagram, it is possible to filter to show only the iiidea that can actually be used with the device by passing the VendorID and/or DeviceID of the device.
Now, in order for your sample app to display the iiidea in the Store, it is necessary to release the iiidea to the Store that works with the device you have registered. Once it is released, you can download the iiidea from the Store and check how the sample app works.
First step is to make the iiidea that works with the device you have registered.
It is important to note where the decision is made as to with which device a particular iiidea works. The next section describes the relationship between iiidea and Piece, and supported devices.
The relationship between iiidea and Piece, and supported devices
The support relationship of whether a particular iiidea works with a particular device or not is determined by whether the Piece within the iiidea works with the device or not.
As shown in the table above, the iiidea in the top row, consisting of Pieces dedicated to Device A and a device-independent Piece, can work with Device A. Conversely, since a Piece that depends on a device other than Device A cannot work with Device A, the iiidea in the bottom row is determined to be an iiidea that cannot work with Device A.
Whether a Piece is device-dependent, or vendor-dependent, or not is declared in PieceJSON. This document describes the PieceJSON specification, but it does not explain the concept of a "device". (It is excluded as it is only relevant for developers who use the RiiiverSDK.) Therefore, the concept of device and/or vendor dependence is also not explained. This section explains how to make the device and/or vendor dependent declaration in PieceJSON.
As shown in the PieceJSON example below, there are items for entering ID with such a key as deviceId and/or vendorId.
{ "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 となります。" ...
In the above example, both deviceId and vendorId are none. none indicates no device dependence. In other words, the Piece in this example can work with any device.
The following is an example of a Piece that is device and vendor dependent.
{ "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" }, ...
The Piece in the above example is declared as a Piece that works only with the application with a DeviceID of "5db923ec51e157128cdef4ea_mTO8FZ4T" and a VendorID of "ghzY5db923ec51e157128cdef4eaPUUr" defined in erconfiguration.json
and AppManager.swift
.
For example, if you declare only your VendorID and set the DeviceID to "none", you can declare a Piece that is available for use with any applications of your organization regardless of the device.
To create an iiidea that works with the sample app you are building and debugging, you need to create a Piece that works with the VendorID/DeviceID you have registered and configure it with that Piece.
Before actually creating an iiidea that works with the sample app, the next section explains how to handle Piece and iiidea before publishing, such as how to debug a Piece during the development phase without publishing.
How to handle iiidea and Piece during the development phase
iiidea can be created using RiiiverApp by simply selecting three Pieces (without coding).
Please refer to this
document for the actual creation process using RiiiverApp.
The Pieces you see when you are creating an iiidea using RiiiverApp are usually publicly available. The diagram below shows how a Piece is published when you develop a Piece.
You will develop your own Piece in the next chapter and upload your Piece on Riiiver. At that time, you will upload the Piece that you have created using a web portal tool called PieceBuilder.
Once your Piece is uploaded to Riiiver, it will be placed in a "testing" status.
Testing
“Testing" means that you are still in the process of evaluating the Piece. In this state, the Piece is not yet public, and nobody other than the developer and the account holder who was registered as a tester at the time of Corporate Account Registration will be aware of the existence of this Piece. During the testing phase, you, as a developer, can log in to Riiiver with RiiiverApp using your email address of your developer account to see all the Pieces in the testing state, and can actually create an iiidea by combining Pieces in the testing state.
If you find a bug during testing and a corrected version is ready, you can update the Piece by uploading the Piece code and/or JSON file again from the edit screen of the relevant Piece on PieceBuilder. You should debug most in this phase.
If you have debugged the Piece sufficiently and wish to publish it, you can submit the relevant Piece using PieceBuilder. Submitted Pieces will be reviewed by the Riiiver office. Submitted Piece will be transitioned to an "awaiting review results" status.
Awaiting review results
The "awaiting review results" status is essentially the same as the "testing" status. It usually takes 1-5 business days for the Riiiver office to provide the review results. Please wait for the review results. The results will be notified to your registered email address.
Once your Piece is approved after the review, your Piece will be made "public" as Review OK.
Public (Review OK)
The “Public" status means anyone can view and choose to use the Piece as a resource for iiidea via RiiiverApp at the time of development.
Declined (Review NG)
If the Piece is unfortunately not approved, it will be placed in a "Declined (Review NG)" status. This status is basically the same as testing in which the Piece is visible only to those involved. Please solve the problem and upload PieceJSON and PieceCore again.
Even after a Piece has been published, it may be withdrawn if a problem is later discovered. In this case, the Piece will also be placed in a "Declined (Review NG)" status. If it is withdrawn after it has been published, users who downloaded it while it was published will be notified with a message that it is no longer available in the description of all iiideas that include the withdrawn Piece. It will no longer be visible via Riiiver App.
This concludes the explanation of the Piece publishing process during the development phase. In the next chapter, "Creating your own original Piece", you will actually create your own iiidea.