Skip to content

Add Python to a SwiftUI application with the BeeWare Briefcase

License

Notifications You must be signed in to change notification settings

radcli14/BeeSwift

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 

Repository files navigation

BeeSwift

Add Python to a SwiftUI application with the BeeWare Briefcase.

This project is derived from the tutorial provided by the BeeWare Project, reduced to those steps that are applicable to iOS development, then extended to add support for Swift. With BeeWare, a template XCode project is generated using briefcase, which also provides a convenient way to manage requirements (Python libraries that are imported in your scripts).

The typical approach is to use Toga for UI development. Many iOS developers are more familiar with UIKit and SwiftUI, or may require specialized iOS features. Here, the Swift interoperability is achieved by creating an AppDelegate class in Objective C and creating an extension for that class in Swift, with supporting headers to form a bridge. An optional step is to include PythonKit which provides a convenient syntax for calling Python objects in Swift, however, the Python C API may also be used.

Setup Virtual Environment

A virtual environment is created below, which serves to isolate the Python environment used in creating the BeeWare project from your system default Python installation. This is not required, but is recommended in the tutorial. For the demonstration, sympy is used as an example "Pure-Python" library that will be tested in the app.

python3 -m venv venv
source venv/bin/activate
pip install sympy
python -m pip install briefcase

Start a New Project

The command below will begin populating a directory with a name derived from the app name (in this example, beeswift) and various default scripts.

briefcase new

There will be several user prompts at this point, where you can choose either the defaults in brackets, or app-specific responses. In this case, the app name Bee Swift and the description are provided, other defaults are accepted by typing enter at the prompt.

Formal Name [Hello World]: Bee Swift
App Name [beeswift]:
Bundle Identifier [com.example]:
Project Name [Bee Swift]: 
Description [My first application]: Add Python to a SwiftUI application with the BeeWare Briefcase
Author [Jane Developer]:
Author's Email [[email protected]]:
Application URL [[https://example.com/beeswift]:
Project License [1]:
GUI Framework [1]:

Set Python Requirements

Next we cd into the beeswift folder (or alternate app name), where we will modify the app requirements code. In this example, we are using sympy, though for your application you will likely have other required Python modules to make your app work.

cd beeswift

Open the file pyproject.toml in a text editor, then scroll to the line that containes the requirements for the iOS app. Specifically make sure this is under the # Mobile deployments line, and is preceeded by [tool.briefcase.app.beeswift.iOS]. Add sympy and the version number to the requires = ... section.

# Mobile deployments
[tool.briefcase.app.beeswift.iOS]
requires = [
    'toga-iOS>=0.3.0.dev34',
    'std-nslog~=1.0.0',
    'sympy==1.11.1'
]

Create the iOS Project

The command below will generate the ./iOS/XCode/Bee Swift/ directory, with Bee Swift.xcodeproj and various other support files. From this point, you may navigate to this project file in Finder, and open it, as the subsequent steps will completed with XCode.

briefcase create iOS

(Optional) Add PythonKit to the iOS Project

In XCode, go to File -> Add Packages, click GitHub on the left hand side, click the plus button on the lower left. In the search field in the upper right, enter the following

https://github.com/pvieito/PythonKit.git

Click Add Package in the lower right corner. If you do choose to skip this optional step, then portions of the code in the AppDelegateExtension created in a later step will not work.

Create Objective C AppDelegate Header

In XCode, in the tree on the left hand side, right click Supporting Files and then New File. Select Header File in the menu, then click Next. Enter the name AppDelegate then click Create, without modifying any defaults. Under the commented section, delete any existing code, and replace with the following:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


@end

Create Objective C AppDelegate Class

In Xcode, in the tree on the left hand side, right click Supporting Files and then New File. Select Objective C File in the menu, then click Next. Enter the name AppDelegate then click Next, and finally Create on the next window, without modifying any defaults. Under the commented section, delete any existing code, and replace with the following.

#import "AppDelegate.h"
#include <Python.h>
#import "Bee_Swift-Swift.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self swiftuiExtension];
    return YES;
}

@end

While much of this is boiler-plate, there are two lines that should be highlighted. First, the #import "Bee_Swift-Swift.h" line will form a bridge for this Objective C file to recognize its Swift counterpart. Second, the [self swiftuiExtension]; will call the corresponding method that will be created in the next step.

Create Swift AppDelegate Extension

In Xcode, in the tree on the left hand side, right click beeswift and then New File. Select Swift File in the menu, then click Next. Enter the name AppDelegateExtension then click Create, without modifying any defaults. On the subsequent popup, click the option to Create Bridging Header. Inside the newly created Bee Swift-Bridging-Header.h file add the following.

#include <Python.h>
#include <dlfcn.h>
#include "AppDelegate.h"

This will expose various C headers that we want to be available to Swift, without which we would not have access to Python or the ability to extend the AppDelegate.

Inside the new AppDelegateExtension.swift file, add the following.

import Foundation
import SwiftUI
import UIKit
import PythonKit

@objc public extension AppDelegate {
    @objc func swiftuiExtension() {
        // Do some Python stuff
        let math = Python.import("math")
        let pi = math.pi
        let piStr = "pi = \(pi)"
        let answer = "sin(1) = \(math.sin(1))"

        // Do some sympy stuff
        let sympy = Python.import("sympy")
        let a = sympy.symbols("a")
        let mechanics = Python.import("sympy.physics.mechanics")
        let b = mechanics.dynamicsymbols("b")
        let ab = a*b
        let abStr = "x = \(ab)"
        
        // Build a SwiftUI
        self.window = UIWindow(frame: UIScreen.main.bounds)
        window.makeKeyAndVisible()
        window.rootViewController = UIHostingController(
            rootView: VStack {
                Text(piStr)
                Text(answer)
                Text(abStr)
            }
        )
    }
}

Here, the sections under the // Do some Python stuff and // Do some sympy stuff comments are included for example only, you will delete them to include your own code. Importantly, the rootView argument to UIHostingController is where you will add your own SwiftUI views, in this case a vertical stack with three text fields is used to show the output of the Python code that preceded it.

Update the Objective C Main File

Modify the call to UIApplicationMain in the main.m script, replacing @PythonAppDelegate with @AppDelegate.

UIApplicationMain(argc, argv, nil, @"AppDelegate");

Add AppDelegate to the Compile Sources

Click on the project (left upper on your Xcode window), then click on Build Phases tab and Compile Sources. Check whether AppDelegate.m is added to the list. If not, click plus button and add `AppDelegate.m.

Run the app

If all the previous steps ran as-intended, then you should be able to run and see a simple app window, showing the value for pi, sine of 1, and a basic symbolic expression.

Result Displayed on iPhone

About

Add Python to a SwiftUI application with the BeeWare Briefcase

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages