# iOS Native Plugin Development Guidelines
# I. Development Environment Preparation
according toNative Plug-In Tool Operating GuidelinesGenerate a multi-terminal plug-in project
install Xcode, get ready iOS development environment
iOS SDK >= 1.1.0
Developer Tools Nightly >= 1.06.2311282
# II. Introduction to Plug-in Project
Here's an example of a multi-terminal plug-in project generated by the tool:
in Finder Open the multiterminal plug-in project directory in
ios
Folder, double-click onNativePlugin.xcodeproj
Open the plug-in projectThe effect when opened is as follows:
# Engineering Catalog Structure Dxplaination
|-- Demo // Examples when developing plug-ins App Project, but there is no actual use in the development of multi-terminal plugins, developers do not need to change the contents of this folder
|-- MyPlugin // Plugin main content, the developer's changes should be made in this directory
|-- WeAppNativePlugin.framework // Multiterminal plugins and multiterminal cores SDK Communication-dependent static libraries
|-- MyPlugin.h
|-- MyPlugin.mm
|-- resources // The resource directory you need to debug the plug-in
|-- arm64 // For real machine debugging
|-- x86 // For simulator debugging
|-- script // Auxiliary scripts for development debugging
# engineering Xcode Configuration Dxplaination
The following configuration is used to create iOS Plug-in project has been set when the completion of the developer should not arbitrarily change
Demo BundleId: The transfer application that needs to be bound to the corresponding multiterminal application iOS Information matching
Of a mobile app bound with multiple apps iOS Information is shown below:
Plug-in bundleId Are automatically generated at the time of project creation, and developers can customize changes
Scheme:scheme The name is fixed as
plugin
And the plug-in build product name is formatted as${pluginId}.framework
Build Phases:Run Script Phase handles the configuration of the build product using the plug-in Demo App, where the order and script content developers should not change.
# run
After completing the configuration according to the above guidelines, you can start running and debugging in Weixin DevTools.
Switch in the WeChat Developer Tool toMultiterminal plug-in modeAfter, selectiOSto hitRun. The tool will open automatically Xcode Engineering.
In the open Xcode Click here.runButton, you can see the sample project running effect
in Xcode On the simulator, click firstLoad multiterminal plugins, Load successfully and then clickCalling the Multiterminal Plugin, can be obtained by vconsole See the return of the plug-in method.
Note: If encountered M1 Computer Simulator button click no response, you can view[guide](https://dev.weixin.qq.com/docs/framework/faq/dev.html#_1% E3%80%81ios-m1-%E7%9A%84%E7%94%B5%E8%84%91%E5%87%BA%E7%8E%B0%E6%A8%A1%E6%8B%9F%E5%99%A8%E6%8C%89%E9%92%AE%E7%82%B9%E5%87%BB%E6%97%A0%E5%93%8D%E5%BA%94%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86)
Subsequent developers modify Mini Program code, project.miniapagejson You just need to keep the tool onThe tool will work with Xcode Communication completes the corresponding resource replacement, the developer only needs to focus on the Xcode Recompile and run. in Xcode build log In, you can see Xcode Logs that communicate with the tool.
The tool's build panel also has related log output:
If the developer finds that the resource replacement does not take effect, Xcode build log Log that does not communicate with the tool or fails to communicate with the tool, please check yourself:
- Tool version Nightly >= 1.06.2311282
- toolSet up->Security settingsThe multiterminal plug-in service port is open in
- The plug-in template has been updated to the latest (plug-in projects can be recreated)
# III. Plugin Development
# Introduction to Call Timing of Multiple-Application and Multiple-Plugins
In the beginning iOS Before the development of multi-terminal plug-ins, understanding the timing of multi-terminal applications and multi-terminal plug-in calls will help developers better.
sequenceDiagram
participant app as Multiterminal application
participant plugin as Multiterminal plugin
app->>app:wx.miniapp.loadNativePlugin Load plugin
app->>plugin: Load plugin framework
plugin->>plugin: Instantiate the plug-in object on load
app->>plugin: Load the plug-in, perform a series of initialization operations (including id Registration, plug-in method registration, plug-ins initPlugin Method call)
app->>app: Hold Plugin Instance pluginInstance
Note over app,plugin: Plugin Load Complete
app->>plugin: pluginInstance.func() Make a call to the plug-in method
# Plugin development
Created in Environmental Preparation iOS Plug-in engineering template, completed for developers:
The following only
Plug-in instantiation
andRegister plugin Id
Is a necessary operation, the remaining operation developers can adjust according to their own needs.
# 1. Plug-in instantiation
__attribute__((constructor))
static void initPlugin() {
[MyPlugin registerPluginAndInit:[[MyPlugin alloc] init]]
}
# 2. Register plugin Id
Using macro methods WEAPP_DEFINE_PLUGIN_ID(pluginId)
Register plugin Id
WEAPP_DEFINE_PLUGIN_ID(YOUR_PLUGIN_ID)
# 3. Define plug-in instance methods initPlugin
// Plug-in initialization method, which is called automatically after registering the plug-in
- (void)initPlugin {
NSLog(@"initPlugin")
}
# 4. Register synchronization method
- Registration method
Using macro methods WEAPP_EXPORT_PLUGIN_METHOD_SYNC(methodName, methodSelector)
Register the synchronization method.
parameter | type | Required | Introductions |
---|---|---|---|
methodName | yes | in js Layer available for acquisition pluginInstance.methodName Make a method call | |
methodSelector | SEL | yes | MyPlugin Plug-in instance methods defined Selector |
- Input and Output Parameters of Synchronization Method
parameter | type | Required | Introductions |
---|---|---|---|
Entry | NSDictionary * | no | in js Layer call pluginInstance.methodName When the incoming Object Type parameter |
Ginseng | Serializable type | no | in js Layer call pluginInstance.methodName The return of |
- Code Examples
OC Implementation of plug-in synchronization method
WEAPP_EXPORT_PLUGIN_METHOD_SYNC(mySyncFunc, @selector(mySyncFunc:))
- (id)mySyncFunc:(NSDictionary *)param {
NSLog(@"mySyncFunc %@", param)
return @"mySyncFunc"
}
JS Side of the method call
wx.miniapp.loadNativePlugin({
pluginId: 'YOUR_PLUGIN_ID',
success: (plugin) => {
console.log('load plugin success')
const ret = plugin.mySyncFunc({ a: 'hello', b: [1,2] })
console.log('mySyncFunc ret:', ret)
},
fail: (e) => {
console.log('load plugin fail', e)
}
})
# 5. Register Asynchronous Methods
- Registration method
Using macro methods WEAPP_EXPORT_PLUGIN_METHOD_ASYNC(methodName, methodSelector)
Register an asynchronous method.
parameter | type | Required | Introductions |
---|---|---|---|
methodName | yes | in js Layer available for acquisition pluginInstance.methodName Make a method call | |
methodSelector | SEL | yes | MyPlugin Plug-in instance methods defined Selector |
- Input and output parameters of asynchronous methods
parameter | type | Required | Introductions |
---|---|---|---|
Entry 1 | NSDictionary * | no | in js Layer call pluginInstance.methodName When the incoming No. 1 individual Object Type parameter |
Entry 2 | WeAppNativePluginCallback | no | in js Layer call pluginInstance.methodName When the incoming No. 2 individual Function Type parameter, in the OC Side may be called back to the js Layer. The callback method supports a parameter of a serializable type |
- Code Examples
OC Plug-in asynchronous method implementation
WEAPP_EXPORT_PLUGIN_METHOD_ASYNC(myAsyncFuncwithCallback, @selector(myAsyncFunc:withCallback:))
- (void)myAsyncFunc: (NSDictionary *)param withCallback:(WeAppNativePluginCallback )callback {
NSLog(@myAsyncFunc %@", param)
callback(@{ @"a": @"1", @"b": @[@1, @2], @"c": @3 })
}
JS Side of the method call
wx.miniapp.loadNativePlugin({
pluginId: 'YOUR_PLUGIN_ID',
success: (plugin) => {
console.log('load plugin success')
plugin.myAsyncFuncwithCallback ({ a: 'hello', b: [1,2] }, (ret) => {
console.log('myAsyncFuncwithCallback ret:', ret)
})
},
fail: (e) => {
console.log('load plugin fail', e)
}
})
# 6. registered AppDelegate method
multifarious iOS Plugin now supports listening AppDelegate method
- application:openURL:options:
- application:continueUserActivity:restorationHandler:
- application:didFinishLaunchingWithOptions:
- application:didRegisterForRemoteNotificationsWithDeviceToken:
- application:didFailToRegisterForRemoteNotificationsWithError
Methods of Use
- The developer can inherit from the
WeAppNativePlugin
The method ofregisterAppDelegateMethod:
To register a wiretap. - A listening method is an instance method of a plug-in object where the method signature is consistent with the method to be monitored,
// in initPlugin Register to monitor
- (void)initPlugin {
NSLog(@"initPlugin")
[self registerAppDelegateMethod:@selector(application:openURL:options:)]
[self registerAppDelegateMethod:@selector(application:continueUserActivity:restorationHandler:)]
}
// when App adopt URL Scheme When it is opened, it is called back here.
- (void)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
NSLog(@"url scheme")
}
// when App adopt Universal Link When it is opened, it is called back here.
- (void)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void ()(NSArray<id<UIUserActivityRestoring>> *__nullable restorableObjects))restorationHandler {
NSLog(@"universal link")
}
# 7. Plugin Event Listening
from iOS SDK >= 1.2.5 Start, support in the JS Side-listening from Native Of events.
- in Native Side is inherited by calling the WeAppNativePlugin The method of
sendMiniPluginEvent:
May be directed to JS Side to send events.
parameter | type | Required | Introductions |
---|---|---|---|
param | NSDictionary * | yes | in js The input obtained by the listening method of the side |
- in JS Side that can use the plug-in instance
onMiniPluginEvent
Method Register Listening
parameter | type | Required | Introductions |
---|---|---|---|
callback | Function | yes | Native Lateral JS The callback triggered when an event is sent on the side, and multiple callbacks can be registered |
- in JS Side that can use the plug-in instance
offMiniPluginEvent
Cancel the wire.
parameter | type | Required | Introductions |
---|---|---|---|
callback | Function | no | Cancel the wire.Cancels all listening callbacks when no callback is specified to cancel |
- Code Examples
OC Plug-in asynchronous method implementation
- (void)sendMsg {
[self sendMiniPluginEvent:@{ @"msg": @"this is an event from plugin" }]
}
JS Side of the method call
const listener1 = (param) => {
console.log('onMiniPluginEvent listener1', param)
}
const listener2 = (param) => {
console.log('onMiniPluginEvent listener2', param)
}
wx.miniapp.loadNativePlugin({
pluginId: 'YOUR_PLUGIN_ID',
success: (plugin) => {
plugin.onMiniPluginEvent(listener1)
plugin.onMiniPluginEvent(listener2)
}
})
# 8. Copy plug-in resources to main package
In general, the source files that plug-ins rely on are packaged and placed in dynamic libraries. If the developer needs to place the source file directly in the main package, it is available in the plugin project's MiniPlugin.bundle/PluginConfig.plist
Fill in the configuration CopyResourcesToMainBundle
As shown in the following figure, when a multiterminal application is built, the MiniPlugin.bundle/resource.txt
Copy to the build generated IPA Under the Level Directory.
Note: Source files to be copied to the main package should be placed in the
MiniPlugin.bundle
In.
# 9. Copy the Mini Program's resources into the plug-in
When using plug-ins, you can copy the resources in the Mini Program directory to the plug-in you use.
In the visual configuration of the project.miniapagejson file, under the plug-ins used, you can see "Add files to native plug-ins," configuring the relative path to the root path of the Mini Program project.
# 10. Start-on-load plugin
In general, plug-ins are dynamically attached only when loadNativePlugin is used. However, some scenarios require the plugin to be loaded as soon as the app launches.
In the development phase, In the plug-in's Mini Program project project.miniapagejson, configure loadWhenStart: true. You can simulate the app launch and load
"mini-plugin": {
"ios": {
"loadWhenStart": true
}
}
During the use phase, in the visual configuration of the project.miniapagejson file, under the plug-in used, you can see "whether the app loads automatically when it starts."
Tools start support in version 1.06.2405222
# 11. App Extensions
Donut Plugin Development SupportApp ExtensionsSuch as message notification extensions, share components, desktop widgets, etc. xcode In the original development project,[Support development itself appex product](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG /ExtensionCreation.html)。
But in order to be able to use in donut, you need to appex Compiled scheme and target Name set to plugin id At the beginning. The compiled appex product is uploaded when building the plugin.
schemes
targets
At the time of final use, these appex All need to be signed. So the use of plug-ins Mini Program projects need to go to the Apple background configuration corresponding bundle id and Profiles, and added to project.miniapagejson.
"mini-plugin": {
"ios": [
{
"open": true,
"pluginId": "wxaaaaaaaaaaaa",
"pluginVersion": "1.0.0",
"isFromLocal": false,
"loadWhenStart": true,
"appexProfiles": {
"NSE": {
"enable": true,
"bundleID": " xxxx.xxx.xxx .xxx,
"profilePath": "xxxx/xxxx/Development.mobileprovision " ,
"distributeProfilePath": "xxxx/xxxx/Certificate for distribution. mobileprovision "
},
"ShareExt": {
"enable": true,
"bundleID": " xxxx.xxx.xxx .xxx,
"profilePath": "xxxx/xxxx/Development.mobileprovision " ,
"distributeProfilePath": "xxxx/xxxx/Certificate for distribution. mobileprovision "
}
},
"resourcePath": "pluginResources/wxaaaaaaa.json
}
],
"android": []
}
Tools start support in version 1.06.2405222
# to construct
Once the plug-in is debugged, the developer needs to build ${pluginId}.framework
Dynamic library for use by multiple applications.
Provided in the toolto construct iOS Plug-in productOf buttons to help developers quickly build support for arm64 To the specified upload directory. iOS Plug-in products are specified to be placed in the directory build/ios
Next, for subsequent uploading of dynamic libraries.
If the developer has a more personalized build process, they can build their own iOS Plug-in products, and put the plug-in products in the specified directory.
# Build failure positioning
Use in toolsto construct iOS Plug-in product, the essence is to call xcode Commands help developers build. In the event of tool build failure, the developer can ios
Directory to locate the cause of the failure yourself using the following build script:
# Change to your own plugin id
PLUGIN_ID= " YOUR_PLUGIN_ID"
TEMP_BUILD_DIR=$(mktemp -d)
xcodebuild clean -project NativePlugin.xcodeproj -scheme plugin -derivedDataPath $TEMP_BUILD_DIR
xcodebuild -project NativePlugin.xcodeproj -scheme plugin -destination generic/platform=iOS -derivedDataPath $TEMP_BUILD_DIR -configuration Release ARCHS=arm64 ONLY_ACTIVE_ARCH=NO
xcodebuild -project NativePlugin.xcodeproj -scheme plugin -destination "generic/platform=iOS Simulator" -derivedDataPath $TEMP_BUILD_DIR -configuration Release ARCHS=x86_64 ONLY_ACTIVE_ARCH=NO
FAT_PATH=$TEMP_BUILD_DIR/Build/Products
LINKMAP_PATH=$TEMP_BUILD_DIR/Build/Intermediates.noindex
SIMULATOR_LIB_PATH=$FAT_PATH/Release-iphonesimulator
IPHONE_LIB_PATH=$FAT_PATH/Release-iphoneos
Li Po -create $IPHONE_LIB_PATH/$PLUGIN_ID.framework/$PLUGIN_ID $SIMULATOR_LIB_PATH/$PLUGIN_ID.framework/$PLUGIN_ID -output $FAT_PATH/$PLUGIN_ID
# IV. Use CocoaPods Managing Project Dependencies
Developers can refer touse CocoaPods Development iOS plug-in。