Skip to Content

Create a Slider Custom Control in an MDK App (Using Metadata Approach)

test
0 %
Create a Slider Custom Control in an MDK App (Using Metadata Approach)
Details

Create a Slider Custom Control in an MDK App (Using Metadata Approach)

September 10, 2020
Created by
November 22, 2019
Build and run the Mobile Development Kit client with slider custom control functionality for Android and iOS platforms.

You will learn

  • How to register and consume an Extension control in MDK Metadata
  • How to write an extension via NativeScript
  • How to build a Mobile development kit client for iOS and Android
  • How to connect to SAP Cloud Platform Mobile application

Prerequisites

You may clone an existing project from GitHub repository and start directly with step 6 in this tutorial.


To extend the functionality, or customize the look and feel, and behavior of your client app, you can create extension controls other than the already existing MDK built-in controls using the following:

  • NativeScript (TypeScript/JavaScript applicable for both Android and iOS)

  • Swift class (iOS only)

In this tutorial, you will create a Slider extension via NativeScript (in TypeScript language) which will be common for both device platforms.

MDK
Step 1: Set up the application foundation
  1. Launch the Dev space in SAP Business Application Studio.

  2. If you do not see the Welcome page, navigate to View menu → Find Command → search with Welcome to launch the Welcome page.

    MDK
  3. In Welcome page, click New project from template .

    MDK
  4. Select MDK Project and click Next.

    MDK
  5. In Basic Information step, select or provide the below information and click Next:

    Field Value
    MDK Template Type Select Empty from the dropdown
    Your Project Name MDK_Slider
    Your Project Name <default name is same as Project name, you can provide any name of your choice>
    MDK

    More details on MDK template is available in help documentation.

  6. After clicking Next, the wizard will generate your MDK Application based on your selections. You should now see the MDK_Petstore project in the project explorer. As you have already opened the workspace, there is no need to open the generated project in new workspace or to add it to workspace. Ignore the pop-up or click the cross icon to hide the window.

    MDK
Log on to answer question
Step 2: Register an Extension Control

The extension control that you will be creating to extend the functionality of your app can be used as base controls by registering it using the MDK editor.

  1. Expand MDK_Slider project, right-click Extensions | select MDK: Register Extension Control.

    MDK
  2. In Template Selection step, select New and register Metadata Extension Control. Click Next.

    MDK
  3. Provide the below information:

    Field Value
    Control Name mdk_slider
    Module MySliderModule
    Control MySliderExtension
    Class MySliderClass
    Display leave it blank

    Here is the basic definition for properties you defined above:

    Module: It is used to identify the extension control. The path to the extension module under <MetadataProject>/Extensions/.

    Control: The name of the file under the <MetadataProject>/Extensions/<Module>/controls that contains the extension class. If not specified, module name would be used as the value for this property.

    Class: The class name of your custom extension class. The client will check for this class at runtime and if it’s found, your extension will be instantiated. Otherwise, a stub with an error message will be shown.

    Display: This property is used for the image to be displayed on the page editor to represent the extension control. Use the binding button to select an image from the \MDK_Slider\Images folder.

    MDK

    You will refer all these properties in step 4.

  4. In Schema Information step, click Next. For this tutorial, you will not need any schema.

    MDK

    Here you can define the properties of the extension control or import a property sample.

  5. Click Finish to confirm.

    Some additional files and folders are added to the Extensions folder. You will learn more about it in following steps.

    MDK

    You can find more details about registering extension control in this guide.

How can you extend the capabilities of the Mobile Development Kit (MDK)?
×
Step 3: Consume Extension Control in MDK Metadata

You will add this registered control in a Form Cell page.

  1. Create a new page of Form Cell type.

    Right-click the Pages folder | MDK: New Page | Form Cell Page | Next.

    MDK

    A Form Cell Page is suitable for pages that generate new objects or modify existing objects. It includes a form cell container by default. You can add form sections, multiple containers or action controls to this page. Under each container section, you can add various container items.

    You can find more details about Form Cell page.

  2. Enter the Page Name as SliderExtension and click Next and the Finish on the Confirmation step.

    MDK
  3. In MDK Page Editor, drag & drop the registered mdk_slider control on the page area.

    MDK
  4. You will set the height for the control.

    In the Properties section, scroll down to the Dimension section and set the Height to 72.

    MDK
  5. You will now set minimum & maximum counter value for the control.

    Scroll down to the Extension Properties, and paste the following information:

    {
      "MaxValue": 200,
      "MinValue": 10,
      "Title": "Counter"
    }
    
    MDK
  6. You will fetch the value of the Slider control and would display this value in a message.

    Right-click the SliderExtension.page, open it with Code Editor.

    MDK

    Rename the value for _Name property to MyExtensionControlName.

    MDK
  7. Create a new Message action.

    Right-click the Actions folder | MDK: New Action | choose MDK Message Actions in Category | click Message Action | Next.

    MDK

    Provide the below information:

    Property Value
    Action Name ShowMessage
    Type Select Message from the dropdown
    Message #Control:MyExtensionControlName/#Value
    Title Value of the Slider is:
    OKCaption OK
    OnOK --None--
    CancelCaption leave it blank
    OnCancel --None--
    MDK

    Here MyExtensionControlName is the name of the control that you renamed in code editor.

    Click Next and then Finish on the confirmation step.

  8. You will add an item on action bar in SliderExtension.page and set ShowMessage.action on its onPress event.

    In SliderExtension.page, drag and drop an Action Bar Item to the upper right corner of the action bar.

    MDK
  9. Click the link icon to open the object browser for the System Item property.

    Double click the Save type and click OK.

    MDK
  10. In the Properties pane | Events tab, click the link icon for the OnPress property to open the object browser, bind it to ShowMessage.action.

    MDK
  11. You can also add an input field where you can provide a manual entry for the slider value and the counter will adapt accordingly.

    For this, first you will write a business logic to set the extension value and then bind it to the input field.

    Right-click the Rules folder | New File.

    MDK

    Enter the file name SetExtensionValue.js, click OK.

    Copy and paste the following code.

    export default function SetExtensionValue(controlProxy) {
        console.log("In SetExtensionValue");
        let srcValue = controlProxy.getValue();
        let targetCtrl = controlProxy.evaluateTargetPath("#Page:SliderExtension/#Control:MyExtensionControlName");
        targetCtrl.setValue(srcValue);
    }
    
    MDK
  12. Save the changes to the SetExtensionValue.js file.

  13. In SliderExtension.page, drag and drop a Simple Property item control below the slider control.

    MDK
  14. Provide the following information:

    Property Value
    Caption Manual Entry
    isEditable Select true from the dropdown
    placeholder Enter number to set the slider ext's value
    MDK
  15. Navigate to Events tab, click the link icon for the OnValueChange property to open the object browser, bind it to SetExtensionValue.js.

    MDK
Log on to answer question
Step 4: Implement Extension using metadata approach
  1. In Extensions folder, create additional files & folders. You will write individual implementation for Android and iOS platform. Final structure should look like as per below.

    MDK
    Extensions
    ├── MySliderModule
    │   └── controls
    │       ├── MySliderPlugin
    │       │   ├── android
    │       │   │   └── MySlider.ts
    │       │   ├── ios
    │       │   │   └── MySlider.ts
    │       │   └── MySlider.ts
    │       └── MySliderExtension.ts
    └── tsconfig.json
    
  2. In MySliderPlugin/android/MySlider.ts file, copy and paste the following code.

    import { Observable } from 'tns-core-modules/data/observable';
    import { View } from 'tns-core-modules/ui/core/view';
    import { layout } from 'tns-core-modules/ui/core/view';
    import { device as Device } from 'tns-core-modules/platform';
    /*
      This is a way to keep iOS and Android implementation of your extension separate
      We will encapsulate the MySlider class definition inside a function called GetMySliderClass
      This is so that the class definition won't be executed when you load this javascript
      via require function.
      The class definition will only be executed when you execute GetMySliderClass
    */
    declare var com: any;
    declare var android: any;
    export function GetMySliderClass() {
        /**
         * IMPLEMENT THE ANDROID VERSION OF YOUR PLUGIN HERE
         * In this sample you have 2 controls a label and a seekbar (slider)
         * You extends this control with Observable (View) class so that you can accept listeners
         *  and notify them when UI interaction is triggered
         */
        function getPadding() {
            // Return left & right padding in dp
            // For tablet you want 24dp, for other type you use 16dp
            return Device.deviceType === 'Tablet' ? 24 : 16;
        }
    
        class MySlider extends View {
            private _androidcontext;
            private _label;
            private _labelText = "";
            private _seekbar;
            private _layout;
            private _value = 0;
            private _min = 0; //Used to track min for API 25 or lower
    
            private updateText() {
                this._label.setText(this._labelText + "(" + this._value + ")")
            }
    
            public constructor(context: any) {
                super();
                this._androidcontext = context;
                this.createNativeView();
            }
    
            /**
             * Creates new native controls.
             */
            public createNativeView(): Object {
                //Create an Android label
                this._label = new android.widget.TextView(this._androidcontext);
                const labelBottomPaddingInPx = layout.round(layout.toDevicePixels(8)); // For top & bottom padding, always 16dp
                this._label.setPadding(0, 0, 0, labelBottomPaddingInPx);
                this._label.setLayoutParams(new android.view.ViewGroup.LayoutParams(-1, -2));
    
                //Create an Android seekbar
                this._seekbar = new android.widget.SeekBar(this._androidcontext);
                this._seekbar.setLayoutParams(new android.view.ViewGroup.LayoutParams(-1, -2));
    
                //Create a LinearLayout container to contain the label and seekbar
                this._layout = new android.widget.LinearLayout(this._androidcontext);
                this._layout.setOrientation(android.widget.LinearLayout.VERTICAL);
                this._layout.setLayoutParams(new android.view.ViewGroup.LayoutParams(-1, -1));
    
                const hortPaddingInPx = layout.round(layout.toDevicePixels(getPadding()));
                const vertPaddingInPx = layout.round(layout.toDevicePixels(16)); // For top & bottom padding, always 16dp
                this._layout.setPadding(hortPaddingInPx, vertPaddingInPx, hortPaddingInPx, vertPaddingInPx);
                this._layout.addView(this._label);
                this._layout.addView(this._seekbar);
                this.setNativeView(this._layout);
                return this._layout;
            }
    
            /**
             * Initializes properties/listeners of the native view.
             */
            initNativeView(): void {
                console.log("initNativeView called");
                // Attach the owner to nativeView.
                // When nativeView is tapped you get the owning JS object through this field.
                (<any>this._seekbar).owner = this;
                (<any>this._layout).owner = this;
                super.initNativeView();
    
                //Attach a listener to be notified whenever the native Seekbar is changed so that you can notify the MDK Extension
                this._seekbar.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener({
                    onStartTrackingTouch(seekBar: any) {
                        // You do not have any use for this event, so do nothing here
                    },
                    //This handler function will be called when user let go of the handle
                    // This is where you will trigger an event called "OnSliderValueChanged" to the MDK Extension Class
                    onStopTrackingTouch(seekBar: any) {
                        var eventData = {
                            eventName: "OnSliderValueChanged",
                            object: seekBar.owner,
                            value: seekBar.owner._value
                        };
                        seekBar.owner.notify(eventData);
                    },
                    //This handler function will be called whenever the slider's value is changed
                    // i.e. whenever user drag the slider's handle
                    onProgressChanged(seekBar: any, progress: number, fromUser: boolean) {
                        seekBar.owner._value = progress;
                        seekBar.owner.updateText();
                    }
                }));
            }
    
            /**
             * Clean up references to the native view and resets nativeView to its original state.
             * If you have changed nativeView in some other way except through setNative callbacks
             * you have a chance here to revert it back to its original state
             * so that it could be reused later.
             */
            disposeNativeView(): void {
                // Remove reference from native view to this instance.
                (<any>this._seekbar).owner = null;
                (<any>this._layout).owner = null;
    
                // If you want to recycle nativeView and have modified the nativeView
                // without using Property or CssProperty (e.g. outside our property system - 'setNative' callbacks)
                // you have to reset it to its initial state here.
            }
    
            //Must return the native view of the control for MDK FormCell and Section Extension
            public getView(): any {
                return this._layout;
            }
    
            public setText(newText: string): void {
                if (newText != null && newText != undefined) {
                    this._labelText = newText;
                    this._label.setText(newText);
                }
            }
    
            public setValue(newVal: number): void {
                if (newVal != null && newVal != undefined) {
                    this._value = newVal;
                    this.updateText();
                    if (this._seekbar.getProgress() < this._min) {
                        this._seekbar.setProgress(this._min);
                    }
                    else {
                        this._seekbar.setProgress(newVal);
                    }
                }
            }
    
            public setMinValue(newMin: number): void {
                if (newMin != null && newMin != undefined) {
                    if (Device.sdkVersion >= 26) { //setMin is only available in set API Level 26 or newer
                        this._seekbar.setMin(newMin);
                    }
                    else {
                        this._min = newMin;
                        if (this._seekbar.getProgress() < this._min) {
                            this._seekbar.setProgress(this._min);
                        }
                    }
                }
            }
    
            public setMaxValue(newMax: number): void {
                if (newMax != null && newMax != undefined) {
                    this._seekbar.setMax(newMax);
                }
            }
        }
        return MySlider;
    }
    

    In your import function, if you see errors related to tns-core-modules or mdk-core, you can ignore them. There is currently no reference of such libraries in the MDK editor.

  3. Save the MySliderPlugin/android/MySlider.ts file.

  4. In MySliderPlugin/iOS/MySlider.ts file, copy and paste the following code.

    import { View } from 'tns-core-modules/ui/core/view';
    
    /*
      This is a way to keep iOS and Android implementation of your extension separate
      You will encapsulate the MySlider class definition inside a function called GetMySliderClass
      This is so that the class definition won't be executed when you load this javascript
      via require function.
      The class definition will only be executed when you execute GetMySliderClass
    */
    export function GetMySliderClass() {
        /**
         * IMPLEMENT THE IOS VERSION OF YOUR PLUGIN HERE
         */
    
        // This is a class that handles the native event callbacks
        class SliderHandler extends NSObject {
    
            //This handler function will be called whenever the slider's value is changed
            // i.e. whenever user drag the slider's handle
            public valueChanged(nativeSlider: UISlider, nativeEvent: _UIEvent) {
                nativeSlider.value = Math.round(nativeSlider.value);
                const owner: MySlider = (<any>nativeSlider).owner;
                if (owner) {
                    owner.setValue(nativeSlider.value);
                }
            }
    
            //This handler function will be called when user let go of the handle
            // This is where you will trigger an event called "OnSliderValueChanged" to the MDK Extension Class
            public afterValueChanged(nativeSlider: UISlider, nativeEvent: _UIEvent) {
                nativeSlider.value = Math.round(nativeSlider.value);
                const owner: MySlider = (<any>nativeSlider).owner;
                if (owner) {
                    owner.setValue(nativeSlider.value);
                    var eventData = {
                        eventName: "OnSliderValueChanged",
                        object: owner,
                        value: nativeSlider.value
                    };
                    owner.notify(eventData);
                }
            }
    
            public static ObjCExposedMethods = {
                "valueChanged": { returns: interop.types.void, params: [interop.types.id, interop.types.id] },
                "afterValueChanged": { returns: interop.types.void, params: [interop.types.id, interop.types.id] }
            };
        }
    
        const handler = SliderHandler.new();
    
        class MySlider extends View {
            private _label;
            private _labelText = "";
            private _slider;
            private _layout;
            private _value = 0;
    
            private updateText() {
                this._label.text = this._labelText + "(" + this._value + ")";
            }
    
            public constructor(context: any) {
                super();
                this.createNativeView();
            }
    
            /**
             * Creates new native controls.
             */
            public createNativeView(): Object {
                //Create the Stack view - this is the main view of this extension
                this._layout = UIStackView.new();
                //Configuring the paddings around the stack view
                this._layout.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth];
                this._layout.layoutMarginsRelativeArrangement = true;
                let inset = new NSDirectionalEdgeInsets();
                inset.top = 8; inset.leading = 16; inset.bottom = 8; inset.trailing = 16;
                this._layout.directionalLayoutMargins = inset;
                // Set the layout stacking to be vertical
                this._layout.axis = UILayoutConstraintAxis.Vertical;
    
                //Create the label view
                this._label = UILabel.new();
                this._label.font = this._label.font.fontWithSize(15); //Set font size
                this._label.textColor = UIColor.colorWithRedGreenBlueAlpha(106 / 255, 109 / 255, 112 / 255, 1.0); //Set text color
                this._layout.setCustomSpacingAfterView(4, this._label); //Set the bottom margin of label
    
                //Create the slider control
                this._slider = UISlider.new();
    
                //Assign a handler for whenever value changed i.e. when user is dragging the slider handle
                this._slider.addTargetActionForControlEvents(handler, "valueChanged", UIControlEvents.ValueChanged);
                //Assign a handler for when user let go of the handle
                this._slider.addTargetActionForControlEvents(handler, "afterValueChanged", UIControlEvents.TouchUpInside | UIControlEvents.TouchUpOutside);
    
                //Add the label and slider to the stack view
                this._layout.addArrangedSubview(this._label);
                this._layout.addArrangedSubview(this._slider);
    
                //store the native view
                this.setNativeView(this._layout);
    
                //return the stack view
                return this._layout;
            }
            /**
             * Initializes properties/listeners of the native view.
             */
            initNativeView(): void {
                // Attach the owner to nativeViews.
                // When nativeViews are tapped you get the owning JS object through this field.
                (<any>this._slider).owner = this;
                (<any>this._layout).owner = this;
                super.initNativeView();
            }
    
            /**
             * Clean up references to the native view and resets nativeView to its original state.
             * If you have changed nativeView in some other way except through setNative callbacks
             * you have a chance here to revert it back to its original state
             * so that it could be reused later.
             */
            disposeNativeView(): void {
                // Remove reference from native view to this instance.
                (<any>this._slider).owner = null;
                (<any>this._layout).owner = null;
    
                // If you want to recycle nativeView and have modified the nativeView
                // without using Property or CssProperty (e.g. outside our property system - 'setNative' callbacks)
                // you have to reset it to its initial state here.
            }
    
            //Must return the native view of the control for MDK FormCell and Section Extension
            public getView(): any {
                return this._layout;
            }
    
            public setText(newText: string): void {
                if (newText != null && newText != undefined) {
                    this._labelText = newText;
                    this._label.text = newText;
                }
            }
    
            public setValue(newVal: number): void {
                if (newVal != null && newVal != undefined) {
                    this._value = newVal;
                    this.updateText();
                    this._slider.value = newVal;
                }
            }
    
            public setMinValue(newMin: number): void {
                if (newMin != null && newMin != undefined) {
                    this._slider.minimumValue = newMin;
                }
            }
    
            public setMaxValue(newMax: number): void {
                if (newMax != null && newMax != undefined) {
                    this._slider.maximumValue = newMax;
                }
            }
        }
    
        return MySlider;
    }
    
  5. Save the MySliderPlugin/iOS/MySlider.ts file.

  6. In MySliderPlugin/MySlider.ts file, copy and paste the following code.

    import * as application from 'tns-core-modules/application';
    
    export let MySlider;
    let MySliderModule;
    /*
    This is a sample of how to implement iOS and Android codes separately in a metadata extension.
    Because all ts files in metadata Extensions folder will be bundled together using webpack,
    if you execute any iOS codes in Android vice versa, it will likely cause issue such as crash.
    
    By splitting the implementation into different files and encapsulate them in a function, it allows
    us to load only the required module for the platform at runtime.
    */
    if (!MySlider) {
        //Here you will check what platform the app is in at runtime.
        if (application.ios) {
            //if app is in iOS platform, load the MySlider module from ios folder
            MySliderModule = require('./ios/MySlider');
        } else {
            //otherise, assume app is in Android platform, load the MySlider module from android folder
            MySliderModule = require('./android/MySlider');
        }
        // calling GetMySliderClass() will return MySlider class for the correct platform.
        //  See the MySlider.ts in ios/andrid folder for details
        MySlider = MySliderModule.GetMySliderClass();
    }
    
  7. Save the MySliderPlugin/MySlider.ts file.

  8. In MySliderExtension.ts file, replace the code with the following.

    import { BaseControl } from 'mdk-core/controls/BaseControl';
    import { MySlider } from './MySliderPlugin/MySlider'
    
    export class MySliderClass extends BaseControl {
        private _slider: MySlider;
        private _minVal: number = 0;
        private _maxVal: number = 10000;
    
        public initialize(props) {
            super.initialize(props);
    
            //Create the Slider plugin control
            this.createSlider();
            //Assign the slider's native view as the main view of this extension
            this.setView(this._slider.getView());
        }
    
        private createSlider() {
            //Create MySlider and initialize its native view
            this._slider = new MySlider(this.androidContext());
            this._slider.initNativeView();
    
            this._slider.setMinValue(this._minVal);
            this._slider.setMaxValue(this._maxVal);
    
            //Set the slider's properties if "ExtensionProperties" is defined
            let extProps = this.definition().data.ExtensionProperties;
            if (extProps) {
                //In here you will use ValueResolver to resolve binding/rules for the properties
                // This will allow the app to use binding/rules to set the properties' value
    
                // Resolve title's value
                this.valueResolver().resolveValue(extProps.Title, this.context, true).then(function (title) {
                    this._slider.setText(title);
                }.bind(this));
    
                // Resolve min value
                this.valueResolver().resolveValue(extProps.MinValue, this.context, true).then(function (minVal) {
                    if (minVal !== null && minVal !== undefined) {
                        this._minVal = minVal;
                        this._slider.setMinValue(this._minVal);
                    }
                }.bind(this));
    
                // Resolve max value
                this.valueResolver().resolveValue(extProps.MaxValue, this.context, true).then(function (maxVal) {
                    if (maxVal !== null && maxVal !== undefined) {
                        this._maxVal = maxVal;
                        this._slider.setMaxValue(this._maxVal);
                    }
                }.bind(this));
    
                // Resolve value
                this.valueResolver().resolveValue(extProps.Value, this.context, true).then(function (value) {
                    this.setValue(value, false, false);
                }.bind(this));
            }
    
            //Set up listener for MySlider's OnSliderValueChanged event that will be triggered when user let of the slider's handle
            // It's eventData object contain a property 'value' that will contain the value of the slider
            this._slider.on("OnSliderValueChanged", function (eventData) {
                //We will call the setValue
                this.setValue(eventData.value, true, false);
            }.bind(this));
        }
    
        // Override
        protected createObservable() {
            let extProps = this.definition().data.ExtensionProperties;
            //Pass ExtensionProperties.OnValueChange to BaseControl's OnValueChange
            if (extProps && extProps.OnValueChange) {
                this.definition().data.OnValueChange = extProps.OnValueChange;
            }
            return super.createObservable();
        }
    
        public setValue(value: any, notify: boolean, isTextValue?: boolean): Promise<any> {
            //Check the value
            if (value != null && value != undefined && !isNaN(value)) {
                if (typeof value == "string" && value.trim() == "") {
                    return Promise.reject("Error: Value is not a number");
                }
                let val = Number.parseInt(value);
                //Don't let value go lower than permitted minimum or higher than permitted maximum
                val = val < this._minVal ? this._minVal : val;
                val = val > this._maxVal ? this._maxVal : val;
    
                if (this._slider) {
                    //Set the slider's value
                    this._slider.setValue(val);
                }
                //Store the value. The observable will trigger "OnValueChange" to the MDK app
                // MDK app can register to this event in the metadata with property "OnValueChange"
                return this.observable().setValue(val, notify, isTextValue);
            } else if (isNaN(value)) {
                return Promise.reject("Error: Value is not a number");
            }
            return Promise.resolve();
        }
    
        public viewIsNative() {
            return true;
        }
    }    
    
  9. Save the MySliderExtension.ts file.

  10. In tsconfig.json file, copy and paste the following code.

    {
        "compilerOptions": {
            "module": "commonjs",
            "target": "es5",
            "experimentalDecorators": true,
            "emitDecoratorMetadata": true,
            "removeComments": true,
            "inlineSourceMap": false,
            "sourceMap": false,
            "noEmitOnError": false,
            "noEmitHelpers": true,
            "declaration": true,
            "lib": [
                "es6",
                "dom"
            ],
            "baseUrl": ".",
            "paths": {
                "tns-core-modules/*": [
                    "./node_modules/tns-core-modules/*"
                ],
                "mdk-sap": [
                    "./node_modules/mdk-sap"
                ],
                "toolbar-plugin": [
                    "./node_modules/toolbar-plugin"
                ],
                "zip-plugin": [
                    "./node_modules/zip-plugin"
                ]
            }
        },
        "exclude": [
            "node_modules",
            "platforms",
            "modules",
            "plugins",
            "build.definitions"
        ]
    }
    

    This file is used for using types defined in MDK SDK or NativeScript. You can find more details about it in help documentation.

  11. Save the tsconfig.json file.

Log on to answer question
Step 5: Set first page as the extension page

In the template generated project, there is already a page called Main.page which is also the page that opens after successful onboarding. For this tutorial, you will change the default behavior of the app launch.

Double click the Application.app file, select the SliderExtension.page for the Main Page field.

MDK
Log on to answer question
Step 6: Deploy and activate application

So far, you have learned how to build an MDK application in the SAP Business Application Studio editor. Now, we deploy this application definition to Mobile Services.

  1. Right-click Application.app and select MDK: Deploy.

    MDK
  2. Verify the URL and Click Enter on your keyboard.

    MDK

    SAP Business Application Studio pre-populates the end-point of the environment it is running in. If you want to connect to a different environment, modify the API endpoint by copying it from your target SAP Cloud Platform account: SAP Cloud Platform Cockpit → Sub-account → API Endpoint

  3. Select the organisation in which you have enabled Mobile Services.

    MDK
  4. Select the space in which you have enabled Mobile Services.

    MDK
  5. Select the an application from Mobile Services.

    MDK

    Upon successful setup, you should see Deploy Succeeded message.

    MDK

    MDK editor stores deployment details in .project.json file. When you deploy to same configuration next time, you will not be asked for above details, MDK editor will pick up these details from .project.json file.

Log on to answer question
Step 7: Populate the QR code for app onboarding

SAP Business Application Studio has a feature to generate QR code for app onboarding.

Double-click the Application.app to open it in MDK Application Editor and click Application QR Code icon to populate the QR code.

MDKMDK
Log on to answer question
Step 8: Run the app in MDK client

Make sure you are choosing the right device platform tab above. Once you have scanned and onboarded using the onboarding URL, it will be remembered. When you Log out and onboard again, you will be asked either to continue to use current application or to scan new QR code.

Follow these steps to on-board the MDK client.

Once you accept app update, you see Slider control.

MDK

Follow these steps to on-board the MDK client.

Once you accept app update, you see Slider control.

MDK

Congratulations! You have successfully created a Slider Custom Control in your MDK App Using Metadata Approach and you are now all set to Add NativeScript Plugins in an MDK App.

Log on to answer question

Next Steps

Back to top