ScandiPWA
Create Magento AppCreate ScandiPWA AppUser ManualGitHub
  • Why Scandi
  • πŸš€Quick-start Guide
  • πŸ—ΊοΈRoadmap
  • Introduction to the Stack
    • CMA, CSA, and ScandiPWA
    • Challenges
  • Setting up Scandi
    • Storefront Mode Setup
      • Proxying requests to server
    • Magento Mode Setup
    • Existing Magento 2 setup
    • Magento Commerce Cloud setup
    • Updating to new releases
      • Storefront mode upgrade
      • Magento mode upgrade
      • CMA upgrade
      • CSA upgrade
      • Custom ScandiPWA composer dependency update
      • Local ScandiPWA Composer Package Setup
    • Docker Setup [deprecated]
      • Legacy Docker setup
      • Migrating to CMA & CSA
  • Developing with Scandi
    • Override Mechanism
      • Overriding JavaScript
        • Overriding classes
        • Overriding non-classes
      • Overriding Styles
      • Overriding the HTML / PHP
      • Parent Themes
    • Extensions
      • Creating an extension
      • Installing an extension
      • Migrating from 3.x to 4.x
      • Publishing an extension
      • Extension Terminology
    • Working With Magento
      • Magento troubleshooting
      • Working with Magento modules
      • Working with GraphQL
      • GraphQL Security
      • Working with "granular cache"
    • Developer Tools
      • Debugging in VSCode
      • ScandiPWA CLI
      • Configuring ESLint
      • CSA Commands
    • Deploying Your App
      • Build & Deploy Android app
      • Build & Deploy iOS app
  • Structure
    • Directory Structure
    • Building Blocks
      • Components
        • Styling Components
      • Routes
      • Redux Stores
      • GraphQL Queries
      • Global Styles
      • The Util Directory
      • Type Checking
    • Application assets
    • Code Style
      • JavaScript Code Style
      • SCSS Code Style
  • Tutorials
    • Customizing Your Theme
      • Styling
        • Customizing the Global Styles
        • Adding a New Font
        • Overriding a Components Styles
        • Extending a Component's Styles
      • Customizing JavaScript
        • Customizing the Footer Copyright
        • Adding a New Page
        • Adding a Section in My Account
        • Adding a Tab on the Product Page
        • Creating a New Redux Store
    • Payment Method Integration
      • Setting Up for Development
      • Redirecting to the Payment Provider
      • Handling the Customer's Return
    • Creating a Custom Widget
      • Scandi CMS System Overview
      • Creating a Magento Widget
      • Implementing the Rendering
    • Video Tutorials
      • #1 Setting up and talking theory
      • #2 Templating in React
      • #3 Overriding a file
      • #4 Styling the application
      • #5 Patterns of ScandiPWA
    • Dark Mode Extension
    • Deploying Native Apps
    • Product 3D Model Extension
      • Part 1: Magento 3D Model Uploads
      • Part 2: GraphQL API
      • Part 3: Scandi Frontend
    • Social Share, Full Extension Development
      • STEP-1 and 2 Creating Magento 2 Module
      • STEP-3 Backend Configurations Settings
      • STEP-4 Simple GraphQl and Resolver
      • STEP-5 Creating Extension, Base Redux Store
      • STEP-6 Extension plugins
      • STEP-7 GraphQL types, Helpers
      • STEP-8 Query Field and FieldList
      • STEP-9 render Plugins and MSTP Plugin, Component creation
      • STEP-10 SocialShare Component Development
      • STEP-11 SocialShare for CategoryPage
      • TASK-1 Changing LinkedIn to Twitter
      • STEP-12 Comments for Admin Users
      • STEP-13 Final, bugfixes
    • Accessing Magento 2 Controllers
      • STEP-1 Creating Magento 2 Module
      • STEP-2 - Create Magento 2 Frontend Route and Basic Controller
      • STEP-3 Accessing Magento 2 Controller, Bypassing ScandiPWA frontend
      • STEP-4 Creating ScandiPWA Extension with additional dependencies
      • STEP-5 Creating Plugin and Axios request
  • About
    • Support
    • Release notes
    • Technical Information
    • Data Analytics
    • Contributing
      • Installation from Fork
      • Repository structure
      • Code contribution process
      • Submitting an Issue
      • Publishing ScandiPWA
Powered by GitBook
On this page
  • Creating an app (step-by-step)
  • 1. Create a new XCode project
  • 2. Select single view template
  • 3. Go to ViewController.swift
  • 4. Replace its content with the script bellow
  • 5. Create an inject.js file from empty template
  • 6. Replace its content with the script bellow
  • 7. Compile and test the application
  • Publishing the app

Was this helpful?

  1. Developing with Scandi
  2. Deploying Your App

Build & Deploy iOS app

You can package Scandi as a native iOS application

PreviousBuild & Deploy Android appNextDirectory Structure

Last updated 4 years ago

Was this helpful?

To deploy an iOS app, you need to have at least one native feature to be included in the app. We used a barcode scanner to search for items. You can add notifications management or anything else, but you have to add it as native code.

To deploy an iOS application you must have a macOS-powered device.

To display your site in iOS App, you first need to make sure it is deployed online. Then, you can use WebView to display the site inside of an iOS native app. To integrate native feature to the site, we suggest using the following approach:

  1. Create a Swift View Controller

  2. Display WebView inside of this controller

  3. Create a JavaScript file that would be injected into the app

  4. Use WebKit message handlers API to establish communication between WebView and native app

Creating an app (step-by-step)

1. Create a new XCode project

2. Select single view template

3. Go to ViewController.swift

4. Replace its content with the script bellow

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler {
    /// Assuming that the javascript sends message back, this function handles the message
    ///
    /// - Parameters:
    ///   - userContentController: controller
    ///   - message: Message. Can be a String or [String:Any] to a single level.
    func userContentController(
        _ userContentController: WKUserContentController,
        didReceive message: WKScriptMessage
    ) {
        print("something recived");

        let messageBody = message.body as! [String: Any];
        let action = messageBody["action"] as! String;
            
        switch action {
        case "barcodeClick":
            print("barcode was clicked");
            return;
        default:
            return;
        }
    }
    
    lazy var webView: WKWebView = {
        let   webCfg:WKWebViewConfiguration = WKWebViewConfiguration()
        
        // Setup WKUserContentController instance for injecting user script
        var userController:WKUserContentController = WKUserContentController()
        
        var script:String?
        
        // Get the contents of the file `inject.js`
        if let filePath:String = Bundle.main.path(forResource: "inject", ofType:"js") {
            script = try! String(contentsOfFile: filePath, encoding: .utf8)
        }
        
        let userScript:WKUserScript =  WKUserScript(source: script!, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
        
        userController.addUserScript(userScript)
        
        // Add a script message handler for receiving  "nativeProcess" event notifications posted from the JS document using window.webkit.messageHandlers.nativeProcess.postMessage script message
        userController.add(self, name: "nativeProcess")
        
        // Configure the WKWebViewConfiguration instance with the WKUserContentController
        webCfg.userContentController = userController;
        
        let webView = WKWebView(
            frame: CGRect(
                x: 0,
                y: 0,
                width: self.view.frame.width,
                height: self.view.frame.height
            ),
            configuration: webCfg
        )
        
        return webView
    }();
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        self.navigationItem.title = "ScandiPWA"
        self.view.addSubview(webView)
        let urlToLoad = URL(string: "https://tech-demo.scandipwa.com")
        // Do any additional setup after loading the view.
        webView.load(URLRequest(url: urlToLoad!))
    }
}

5. Create an inject.js file from empty template

6. Replace its content with the script bellow

function sendToNative(message) {
    // Initiate the handle for Native process
    const native = window.webkit.messageHandlers.nativeProcess
    native.postMessage(message)
}

function onBarcodeClick() {
    sendToNative({
         action: 'barcodeClick',
     });
}

const BARCODE_SCANNER_ID = 'barcode-scanner';
const SEARCH_FIELD_ID = 'search-field';

function tryRenderingElement() {
    setTimeout(() => {
               if (document.getElementById(BARCODE_SCANNER_ID)) {
               return;
               }
               
               const searchElement = document.getElementById(SEARCH_FIELD_ID);
               
               const barcodeButton = document.createElement('button');
               barcodeButton.id = BARCODE_SCANNER_ID;
               barcodeButton.style.width = '30px';
               barcodeButton.style.height = '30px';
               barcodeButton.style.marginLeft = '1.4rem';
               barcodeButton.style.backgroundImage = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 480 480'%3E%3Cpath d='M80 48H16C7 48 0 55 0 64v64a16 16 0 0032 0V80h48a16 16 0 000-32zM464 336c-9 0-16 7-16 16v48h-48a16 16 0 000 32h64c9 0 16-7 16-16v-64c0-9-7-16-16-16zM464 48h-64a16 16 0 000 32h48v48a16 16 0 0032 0V64c0-9-7-16-16-16zM80 400H32v-48a16 16 0 00-32 0v64c0 9 7 16 16 16h64a16 16 0 000-32zM64 112h32v256H64zM128 112h32v192h-32zM192 112h32v192h-32zM256 112h32v256h-32zM320 112h32v192h-32zM384 112h32v256h-32zM128 336h32v32h-32zM192 336h32v32h-32zM320 336h32v32h-32z'/%3E%3C/svg%3E")`;
               barcodeButton.style.backgroundSize = 'contain';
               barcodeButton.onclick = onBarcodeClick;
               
               const searchFieldWrapper = searchElement.parentNode.parentNode;
               searchFieldWrapper.style.display = 'flex';
               searchFieldWrapper.style.alignItems = 'center';
               searchFieldWrapper.appendChild(barcodeButton);
               
               const searchField = searchElement.parentNode;
               searchField.style.flexGrow = '1';
               }, 0);
}

const pushState = window.history.pushState;
window.history.pushState = function () {
    // Track page changes in React
    pushState.apply(window.history, arguments);
    tryRenderingElement();
};

tryRenderingElement();

7. Compile and test the application

As you can see injecting scripts into WebView is not that hard. When clicking on the barcode icon, the XCode console logs the barcode was clicked message. You can replace this logic with anything that matches your needs.

We will publish the full app code (including the barcode implementation) soon, so you can use it as a reference.

When the app is done, it's time to publish it!

Publishing the app

  1. Go to My Apps click +

  2. Enter app name, category, privacy, pricing

  3. Next, build your app with XCode

    1. For build platform select: Generic iOS Device

    2. Go to Product > Archive and build the app

    3. Select newly created archive, click Distribute App, select iOS AppStore

  4. Find a version of your app, and click Submit for Review

To publish an iOS app, you must be signed up for the Apple Developer Program. You can do this on the official site, .

Login to your

Make screenshots of your application ()

Go back to your

For a more detailed guide, please .

The process of review might take up to 10 days and result in refusal. ScandiPWA does not guarantee your app publishing. Please make sure the app you build complies with .

here
App Store Connect
size guide
App Store Connect
see Chris's guide
AppStore guidelines