WidgetKit
Compose native apps without a code using JSON and load them as NSBundle into another app dynamicly from local or remote locations.
Install / Use
/learn @m8labs/WidgetKitREADME
WidgetKit for iOS 
WidgetKit framework allows you to compose native apps without a code and load them as NSBundle into another app dynamicly from local or remote locations. No executables will be downloaded and loaded into memory, because widgets contain none of them. All logic and data flow are based on NSPredicate and NSExpression.
WidgetKit uses technique of mediating controllers, which were introduced in Cocoa Bindings (
NSControllerand its descendants in AppKit for macOS). Although, this is not direct port of it. Read more about this here.
WidgetKit view controllers consist of predefined and 100% reusable objects (NSObjects), or mediating controllers, which control presentation of views inside their view controller. You put these mediator objects onto the view controllers' scene in the Interface Builder, set their properties via User Defined Runtime Attributes and connect outlets between them and your UI elements. Or, alternatively, you can load all this setup through corresponding JSON files, and that's what will be described in this document.
Features:
- Bind UIKit elements to model's fields with data formatting;
- Handle received JSON data and parse it directly to the CoreData (in the background);
- Send forms (with media content) to any http server using plain UIKit controls;
- Populate
UITableViewandUICollectionViewwith various types of data (JSON, array ofNSObjectorNSManagedObject); - Handle UIControl's interactions, including infinite scroll and pull to refresh;
- Filter content in
UITableViewandUICollectionViewvia text input fields using predicates; - Delete content with respecting its ownership. You set ownership rules in CoreData Model Designer;
- Propagate content object between view controllers on segue;
- Control presentation of particular UI elements in the view controller when specific data changes;
- Calculate views geometry in the background for faster scrolling;
WidgetKit is not a set of ready-to-use views and view controllers. Your UI is completly under your control.
Examples
- WidgetDemo - main example, open it to follow explanations below.
- WidgetHostDemo - widgets loader. This example is on the picture below and uses loading code similar to what is used in the beginning of the Usage section.
To install, download this repo, in Terminal go to the "Samples/***Demo" directory and run
pod installcommand.
- TwitterDemo - complex "real life" example with custom code integration. You can download it here.
Installation
CocoaPods
To install via CocoaPods add this line to your Podfile:
pod 'WidgetKit'
Then run pod install command.
Carthage
To install via Carthage add this to your Cartfile:
github "faviomob/WidgetKit"
Run carthage update --platform iOS to build the frameworks and drag built "*.framework" files into your Xcode project. Then open Build Phases section of your target and add new Copy Files Phase by pressing "+" button at the top left corner. Choose Frameworks as destination and add all the frameworks you've just dragged into the project.
Usage
First, let's see how you can integrate external NSBundle to yout host application. Drag new UIView to your view controller and set its custom class to WidgetView. Create @IBOutlet for this view in your view controller. Also drag UIButton and create @IBAction for it. The whole setup should look like this:
import WidgetKit
class MyHostViewController: UIViewController {
@IBOutlet var remoteWidgetView: WidgetView!
@IBAction func downloadAction(_ sender: UIButton) {
sender.isEnabled = false
remoteWidgetView.download(url: "https://<address>/YourWidget.zip") { widget, error in
sender.isEnabled = true
}
}
}
You will also need to set widgetIdentifier for the widget view so, that it starts with bundleIdentifier of your widget's NSBundle. As alternative to the listing above, you can just set downloadUrl property of your widget view, but you will not be able to track failure or success manually in this case. All these properties you can set in the viewDidLoad method or in the User Defined Runtime Attributes section of the Interface Bulder. You can add as many widgets to the host view as you want, but all of them should have different widgetIdentifier.
Building a Widget
Now, let's see how you can create widget app itself. The easiest way to understand how things work is to open the WidgetDemo sample project and run it.
Concepts
WidgetDemo project contains Main.storyboard file, CoreData Model file and a couple of JSON files: one for each view controller, and one for setting up your networking stack.
Let's look at the "FeedViewController.json" and "NewPostViewController.json" files, which contain setup for our view controllers.
To load this type of files, the view contoller itself should be of
ContentViewControllercustom class or its descendant. Also, therestorationIdentifiershould be set to the name of the JSON file (without extension).
There are four base types of mediator objects you can create in this file, and all of them are inherited from CustomIBObject which in its turn is descendant of the NSObject:
- BaseContentProvider
- BaseDisplayController
- ActionController
- ActionStatusController
For each particular purpose you create one of the descendants of these four major types. For example, for displaying data inside UITableView you should choose TableDisplayController, and for setting view controllers' content object (which will update all binded UI controls), you create ContentDisplayController. For fetching data from CoreData store you connect these BaseDisplayController objects to the ManagedObjectsProvider content provider.
ActionController is an object, that can call some network action that you describe in your networking JSON, or it can call some selector if you set target outlet to it. In case when selector not found, it will try to call network action with the same name instead. The moment, when action happens depends on the concrete descendant of the ActionController. For example, for handling buttons pressing you create ButtonActionController and connect your button to the sender outlet, and OnLoadActionController will be triggered after the viewDidLoad.
More close look on the networking you will find in the Networking section of this document, but in brief, you have one JSON file (actually two: development and production) with a section for each named action, where you put path, httpMethod, parameters, resultType and other attributes of the network call. All parameters are automatically taken and substituted from ActionController. Also you have one common section, where you store your baseUrl and other defaults. After the network request completes, its response will be automatically parsed into CoreData objects in the backgound. The name of the class of objects created you set in the resultType.
Each action controller contains ActionStatusController in its status variable. So you can bind to status.inProgress key path and update your labels and activity indicators accordingly. You can also have independent ActionStatusController object for situations when action was initiated outside of the current view controller. For example, after loading current user, an action of loading feed content will be called automatically as a chain call (read about chained network calls below). Thus, to track the state of this call you need to create separate ActionStatusController object.
Fetch & Display
Ok, enough theory, let's move to our example. If you open "FeedViewController.json" you will find two sections in the root node: objects and elements. The first one should contain mediator objects, and the second one contains bindings for UI elements. You can also use this section to set initial values for properties (see attrs) the same way you do it in the User Defined Runtime Attributes, but additionally arrays are supported.
The widget starts its work from loading current user. In this sample we omit the authentication part of the networking layer, and assume that we already authenticated. To know how to setup real networking with complex authentication process check the TwitterDemo sample app.
To load the current user when widget starts we need OnLoadActionController object:
"currentUserAction": {
"type": "OnLoadActionController",
"attrs": {
"actionName": "currentUser"
}
}
This will initiate the call to the endpoint named "currentUser" and, upon receiving response JSON, Account managed object will be created, becau
Related Skills
node-connect
349.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
