Tutorials
Getting started
Chart interface
Web components
Chart internals
Data integration
Customization
Frameworks and bundlers
Mobile development
Trading
Time Span Events
Term structures
ScriptIQ
Troubleshooting
Glossary
Reference
JSFiddles

Getting Started on Mobile: iOS

This page will discuss how to integrate the ChartIQ mobile SDK into your native iOS app and how to instantiate and interact with a ChartIQ chart. Create a ChartIQ view) is optional if you want to create your app from scratch. The ChartIQ mobile SDK project comes prepackaged with a working application and can be used right out of the box.

Contents:


Overview

The ChartIQ mobile SDK provides a native interface for iOS developers to instantiate and interact with a ChartIQ chart. The interface will create a WKWebView and populate it with a predefined HTML file that loads the ChartIQ JavaScript library, supporting CSS, and a JavaScript “bridge” file which interfaces with the native interface.

What occurs in the WebView will be hidden, automatic, and not dependent on developer configuration. The developer should be able to instantiate the object as they would any other native component and essentially “feel” like they are working with a native component.

iOS Quirks

iOS WebViews do not automatically follow relative paths. You'll need to ensure that your files can be found by iOS. For more information about relative paths in iOS apps, see this tutorial. Or search for "Add files and folders to a project" in the Apple xcode help site.

Important!

Although the mobile SDK for iOS and the JavaScript library may use the same function call names at times, they are not the same, and they are not interchangeable.

  • When using the mobile SDK, follow the documentation in the mobile native API.
  • When directly calling the JavaScript API, follow the documentation in the JavaScript CIQ core library.

Requirements

The list of Requirements can be found here.

Return to the top

Download the ChartIQ mobile SDK

If you have a fresh checkout of the iOS sample application, the latest SDK is included with the master branch. If you want a previous version, please check out the appropriate tag.

Now, let's create a ChartIQ view in the app.

Return to the top


Create a ChartIQ view (optional)

The ChartIQ mobile SDK contains a fully functional sample app that works almost out of the box. The only thing you need to provide the WKWebView with is an HTML file to load. Whether that is from a web server or files bundled with your iOS application is up to you. Unless you want to create your own ViewController and change how data is populated in the chart, you can skip this step and go straight to Initialize and deploy the ChartIQ mobile SDK.

  1. Import the ChartIQ library into your app's ViewController.

    import ChartIQ
    
  2. Create a ChartIQ view in your app's ViewController. Open Chart.storyboard and add a UIView to your ViewController. Adjust the dimensions of the UIView as desired.

  3. Open the Editor Assistant so that your Storyboard and ViewController source file are both visible on the same screen.

  4. Control-drag from your newly added view to your ViewController file.

  5. Name this new association 'chartIQView' of type 'ChartIQView'.

    internal var chartIQView: ChartIQView!
    
  6. Now, in your ViewController, add code to let the chart know how to load your data (see loadChartData).

    This is an example on how to do that using the ChartIQ simulator data-server.

    You should replace the code in the ViewController with your own implementation.

    import UIKit
    import ChartIQ
    
    class ViewController: UIViewController {
    
        // MARK: - Properties
    
        @IBOutlet weak var chartIQView: ChartIQView!
    
        // MARK: - View Life Cycle
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            chartIQView.delegate = self
            chartIQView.dataSource = self
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        // MARK: - Data
    
        // Sample code for loading data form your feed.
        func loadChartData(by params: ChartIQQuoteFeedParams, completionHandler: @escaping ([ChartIQData]) -> Void) {
            let urlString = "https://simulator.chartiq.com/datafeed?identifier=\(params.symbol)" +
                "&startdate=\(params.startDate)" +
                "\(params.endDate.isEmpty ? "" : "&enddate=\(params.endDate)")" +
                "&interval=\(params.interval)" +
            "&period=\(params.period)&seed=1001"
            guard let url = URL(string: urlString) else { return }
            let task = URLSession.shared.dataTask(with: url) { data, response, error in
                guard error == nil else { return }
                guard let data = data else { return }
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.sssZ"
                var chartData = [ChartIQData]();
                let json = try! JSONSerialization.jsonObject(with: data, options: [])
                guard let result = json as? [[String: Any]] else { return }
                result.forEach({ (item) in
                    let close = item["Close"] as? Double ?? 0
                    let dt = item["DT"] as? String ?? ""
                    let date = dateFormatter.date(from: dt)!
                    let high = item["High"] as? Double ?? 0
                    let low = item["Low"] as? Double ?? 0
                    let open = item["Open"] as? Double ?? 0
                    let volume = item["Volume"] as? Int ?? 0
                    let _data = ChartIQData(date: date, open: open, high: high, low: low, close: close, volume: Double(volume), adj_close: close)
                    chartData.append(_data)
                })
                completionHandler(chartData)
            }
            task.resume()
        }
    }
    
    // MARK: - ChartIQDelegate
    
    extension ViewController: ChartIQDelegate {
    
        func chartIQViewDidFinishLoading(_ chartIQView: ChartIQView) {
            chartIQView.setDataMethod(.pull)
            chartIQView.setSymbol("APPL")
        }
    
    }
    
    // MARK: - ChartIQDataSource
    
    extension ViewController: ChartIQDataSource {
    
        public func pullInitialData(by params: ChartIQQuoteFeedParams, completionHandler: @escaping ([ChartIQData]) -> Void) {
            // put code for initial data load from your feed here
            loadChartData(by: params, completionHandler: completionHandler)
        }
    
        public func pullUpdateData(by params: ChartIQQuoteFeedParams, completionHandler: @escaping ([ChartIQData]) -> Void) {
    	      // put code for initial data load from your feed here
            loadChartData(by: params, completionHandler: completionHandler)
        }
    
        public func pullPaginationData(by params: ChartIQQuoteFeedParams, completionHandler: @escaping ([ChartIQData]) -> Void) {
    	      // put code for initial data load from your feed here
            loadChartData(by: params, completionHandler: completionHandler)
        }
    }
    

Now we're ready to initialize the ChartIQ mobile SDK and connect it to the ChartIQ view.

Return to the top


Initialize and deploy the ChartIQ mobile SDK

  1. Finish initializing the mobile SDK in your ChartIQViewController. See the setupChartIQView and chartIQViewDidFinishLoading methods in ChartIQViewController for examples.

    • Copy sample-template-native-sdk.html from the mobile directory into the root directory of the library package.
    • Make sure the chartUrl string is set to the path where your ChartIQ HTML5 library is deployed so your WebView can be initialized. For our application, the URL is set in the AppDelegate file.
    • Note: If you are deploying your app using localhost, it is important to know that you have to use your local machine IP address for the URL path. Do not use "localhost" or "127.0.0.1", as the Xcode Emulator or real device won't recognize that path because the app is technically on it's own device.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // !!!!! adjust `deploypath` as needed match to match the path
        // to get to sample-template-native-sdk.html
        let chartUrl = "http://deploypath/template-native-sdk.html"
        ChartIQView.start(url: chartUrl)
        return true
    }
    

    Loading sample-template-native-sdk.html as a local resource

    By default, this app is configured to load the sample HTML template and corresponding library files remotely via HTTP.

    If instead you will load the library files as local resources, you'll need to ensure that your files can be found by iOS. Follow this tutorial or search for "Add files and folders to a project" in the Apple xcode help site.

    Then modify your chartUrl to the following:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let url = Bundle.main.url(forResource: "chartiq/sample-template-native-sdk", withExtension: "html")
    try! ChartIQView.start(url: (url?.absoluteString)!)
    return true
    }
    

    If you are planning on bundling the library with your application, please let us know so we can send you a suitable package. The standard domain locked library will not work in this case. See Sidebar: Advantages of Remote Deployment for details on these two approaches.

  2. Build and run your app. You should see a ChartIQ view loaded and populated with a chart.

Return to the top

Extend the ChartIQ mobile SDK

So now that you have the chart working, it will be useful to know how to extend the the mobile SDK. A simple example of how to add your own function to the nativeSdkBridge.js file is in the Getting Started on Mobile tutorial, but how does the iOS native code call the JavaScript functions? The iOS WkWebview has native methods, evaluateJavaScript and evaluateJavaScriptWithReturn, that take a string that will represent the call you want to make in JavaScript. An example using the files that come with the iOS mobile SDK and ChartIQ SDK is below.

Let's say you want a method that will return the series object that represents all the series that are currently drawn on the chart.

  1. First modify your nativeSdkBridge.js file that is packaged with your ChartIQ SDK (chartiq/mobile/nativeSdkBridge.js).

    //
    CIQ.MobileBridge.getAllSeries = function () {
    	const allSeries = CIQ.clone(stxx.chart.series); // clone the object if you plan on modifying any of the fields before passing back to iOS
    	return JSON.stringify(seriesObj); // iOS needs to return a string if you are passing back an object
    };
    
  2. Now add a wrapper method to ChartIQView.swift. Since we are returning a value, we will need to use evaluateJavaScriptWithReturn method.

    public func getAllSeries() -> String? {
        let script = "CIQ.MobileBridge.getAllSeries();"
        return webView.evaluateJavaScriptWithReturn(script)
    }
    

    Alternatively you can call the chart engine JavaScript object (stxx in the example below) directly from the iOS side. This is not encouraged as putting a helper method in the nativeSdkBridge script allows for easier debugging and less confusion when one script is providing a layer of abstraction.

    public func getAllSeries() -> String? {
        let script = "stxx.chart.series;" // not encouraged
        return webView.evaluateJavaScriptWithReturn(script)
    }
    
  3. This new iOS method can now be called by the ChartIQView object.

    private func messingWithSeries() {
    	// series business
    	...
    	let allTheSeries = chartIQView.getAllSeries()
    	let convertedSeries = try? JSONSerialization.jsonObject(with: data, options: [])
    	// now do what you want with the series data
    	...
    }
    

The ability to extend the ChartIQ mobile SDK is powerful, as it gives you access to all the functions that the ChartIQ SDK uses. We cannot one-to-one map all the ChartIQ functions, as that would create a bridge file much too large, but if there are certain functions you absolutely need, we encourage you to extend them in the nativeSdkBridge.

Return to the top

Next steps

See the following: