├── README.md └── OnBoardingKit-Demo.swift /README.md: -------------------------------------------------------------------------------- 1 | # OnBoardingKit Demo 2 | 3 | A Swift file demonstrating how to use Apple's private OnBoardingKit framework. Because this code relies on dynamically loading a private framework, it should not be used in apps submitted to Apple's App Store. 4 | 5 | Screenshot 2024-11-02 at 11 26 14 6 | -------------------------------------------------------------------------------- /OnBoardingKit-Demo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OnBoardingKit-Demo.swift 3 | // OnBoardingKit-Demo 4 | // 5 | // Created by Seb Vidal on 21/02/2024. 6 | // 7 | 8 | import UIKit 9 | 10 | class ViewController: UIViewController { 11 | // MARK: - viewDidAppear(_:) 12 | override func viewDidAppear(_ animated: Bool) { 13 | super.viewDidAppear(animated) 14 | 15 | let title: NSString = "OnBoardingKit" 16 | let detailText: NSString = "An example of how to use OnBoardingKit." 17 | let welcomeController = OBWelcomeController(title: title, detailText: detailText, symbolName: nil) 18 | welcomeController.addBulletedListItem(title: "Item 1", description: "A long description of Item 1 that can span across multiple lines.", symbolName: "circle.fill") 19 | welcomeController.addBulletedListItem(title: "Item 2", description: "A long description of Item 1 that can span across multiple lines.", symbolName: "square.fill") 20 | welcomeController.addBulletedListItem(title: "Item 3", description: "A long description of Item 3 that can span across multiple lines.", symbolName: "star.fill") 21 | 22 | welcomeController.addBoldButton(title: "Get Started") { self.dismiss(animated: true) } 23 | welcomeController.addLinkButton(title: "Not Now") { self.dismiss(animated: true) } 24 | 25 | present(welcomeController.viewController, animated: true) 26 | } 27 | } 28 | 29 | class OBWelcomeController { 30 | // MARK: - Private Properties 31 | private static var dynamicLibraryLoaded: Bool = false 32 | 33 | // MARK: - Public Properties 34 | private(set) var viewController: UIViewController! 35 | 36 | // MARK: - init(title:detailText:symbolName:) 37 | init(title: NSString, detailText: NSString, symbolName: NSString?) { 38 | if OBWelcomeController.dynamicLibraryLoaded == false { 39 | dlopen("/System/Library/PrivateFrameworks/OnBoardingKit.framework/OnBoardingKit", RTLD_NOW) 40 | OBWelcomeController.dynamicLibraryLoaded = true 41 | } 42 | 43 | let initWithTitleDetailTextSymbolName = (@convention(c) (NSObject, Selector, NSString, NSString, NSString?) -> UIViewController).self 44 | 45 | let OBWelcomeController = NSClassFromString("OBWelcomeController") as! NSObject.Type 46 | let welcomeController = OBWelcomeController 47 | .perform(NSSelectorFromString("alloc")) 48 | .takeUnretainedValue() as! NSObject 49 | 50 | let selector = NSSelectorFromString("initWithTitle:detailText:symbolName:") 51 | let implementation = welcomeController.method(for: selector) 52 | let method = unsafeBitCast(implementation, to: initWithTitleDetailTextSymbolName.self) 53 | 54 | let title: NSString = "OnBoardingKit" 55 | let detailText: NSString = "A demo of how to use OnBoardingKit." 56 | viewController = method(welcomeController, selector, title, detailText, nil) 57 | } 58 | 59 | // MARK: - Public Methods 60 | func addBulletedListItem(title: NSString, description: NSString, symbolName: NSString, tintColor: UIColor = .tintColor) { 61 | let addBulletedListItemWithTitleDescriptionSymbolNameTintColor = (@convention(c) (NSObject, Selector, NSString, NSString, NSString, UIColor) -> Void).self 62 | let selector = NSSelectorFromString("addBulletedListItemWithTitle:description:symbolName:tintColor:") 63 | let implementation = viewController.method(for: selector) 64 | let method = unsafeBitCast(implementation, to: addBulletedListItemWithTitleDescriptionSymbolNameTintColor.self) 65 | _ = method(viewController, selector, title, description, symbolName, tintColor) 66 | } 67 | 68 | func addBoldButton(title: NSString, action: @escaping () -> Void) { 69 | let OBBoldTrayButton = NSClassFromString("OBBoldTrayButton") as! NSObject.Type 70 | let selector = NSSelectorFromString("boldButton") 71 | let button = OBBoldTrayButton.perform(selector).takeUnretainedValue() as! UIButton 72 | button.configuration?.title = String(title) 73 | button.addAction(UIAction { _ in action() }, for: .touchUpInside) 74 | 75 | let buttonTray = viewController.value(forKey: "buttonTray") as! NSObject 76 | buttonTray.perform(NSSelectorFromString("addButton:"), with: button) 77 | } 78 | 79 | func addLinkButton(title: NSString, action: @escaping () -> Void) { 80 | let OBLinkTrayButton = NSClassFromString("OBLinkTrayButton") as! NSObject.Type 81 | let selector = NSSelectorFromString("linkButton") 82 | let button = OBLinkTrayButton.perform(selector).takeUnretainedValue() as! UIButton 83 | button.configuration?.title = String(title) 84 | button.addAction(UIAction { _ in action() }, for: .touchUpInside) 85 | 86 | let buttonTray = viewController.value(forKey: "buttonTray") as! NSObject 87 | buttonTray.perform(NSSelectorFromString("addButton:"), with: button) 88 | } 89 | } 90 | --------------------------------------------------------------------------------