Skip to content

API/Component Customization

1. Registering Custom APIs

If the applet needs to call some capabilities provided by the host App, and the PhizClip applet SDK is not implemented or cannot be implemented, you can register a custom API to make the applet call the API registered in the App.

Registering a custom API is divided into two scenarios:

  1. a custom API registered for use by native applets.
  2. a custom API registered for use by H5 loaded by the WebView component in the applet.

1.1 Register the applet asynchronous API

Registering functions for a custom asynchronous API

objectivec
/**
 Register Extension Api

 @param extApiName Extended api name
 @param handler Callback
 @return Return registration results
 */
- (BOOL)registerExtensionApi:(NSString *)extApiName handler:(void (^)(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback))handler;

For example, I register a custom PhizClipLogin here so that it can be used directly in the applet.

First, after integrating the SDK in the app, register the custom api:

objectivec
[[FATClient sharedClient] registerExtensionApi:@"PhizClipLogin" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) {
    // xxxx
    callback(FATExtensionCodeSuccess, nil);
}];

Then, create the PhizClipConf.js file in the root directory of the applet, with the following sample configuration:

js
module.exports = {
  extApi: [
    {
      //General Interaction API
      name: 'PhizClipLogin', //Extended api name The api must be implemented on the Native side
      sync: false, //Whether it is synchronous api
      params: {
        //Extend the parameter format of the api to list only the required properties
        url: ''
      }
    }
  ]
}

Note: extApi is an array, so you can register multiple custom APIs.

For more customized API configuration information, please refer to pz.loadExtApi

Finally, call the custom API in the applet, sample code:

js
pz.PhizClipLogin({
  url: 'https://www.baidu.com',
  success: function(res) {
    console.log('Call customEvent success')
    console.log(res)
  },
  fail: function(res) {
    console.log('Call customEvent fail')
    console.log(res)
  }
})

1.2 Register for the applet sync API

Since 2.36.1, PhizClip applet SDK also supports registering custom synchronous APIs.

The functions for registering custom synchronous APIs are:

objectivec
/**
 Register for the Synchronization Extension Api
 @param syncExtApiName Extended api name
 @param handler Call
 @return Return registration results
 */
- (BOOL)registerSyncExtensionApi:(NSString *)syncExtApiName handler:(NSDictionary *(^)(FATAppletInfo *appletInfo, id param))handler;

For example, I register a synchronized applet API here: 1).

1). After initializing the SDK, register and implement the synchronization api.

objectivec
[[FATClient sharedClient] registerSyncExtensionApi:@"PhizClipTestSync" handler:^NSDictionary *(FATAppletInfo *appletInfo, id param) {
    NSLog(@"%p, param:%@", __func__, param);
    NSDictionary *resultDict = @{
                                 @"content":@"This is what the sync api returns",
                                 @"title":@"This is the title returned by the sync api"
    };
    return resultDict;
}];

2). Create PhizClipConf.js file in the root directory of the applet and add the sync api

js
module.exports = {
  extApi: [
    {
      //General Interaction API
      name: 'PhizClipLogin', //Extended api name The api must be implemented on the Native side
      sync: false, //Whether it is synchronous api
      params: {
        //Extend the parameter format of the api to list only the required properties
        url: ''
      }
    },
    {
      name: 'PhizClipTestSync',
      sync: true, // Whether it is synchronous api
      params: {
        name: '',
        title: ''
      }
    }
  ]
}

3). Call in the applet

js
const res = pz.PhizClipTestSync({ name: 'Zhang San', title: 'PhizClip' })
console.log(res.title)

Note that. The input to the custom synchronization api is a dictionary, the return value must also be a dictionary type, and the interior cannot contain objects that cannot be jsonized (e.g. view, custom model). The parameters declared in the params of > PhizClipConf.js must be passed in the call. For example, in my example above, I declared two parameters, name and title, if I use const res = pz.PhizClipTestSync({'name':'Zhang San'}), const res = pz.PhizClipTestSync({}), const res = pz. PhizClipTestSync() will all result in an error being reported and the event cannot be sent to the native. So the params in PhizClipConf.js are better left out or declared as {}.

1.3 Register JS API

The web-view component can be used in the applet to load the H5, and if the H5 also wants to call a capability of the host API, you can use this method to register an API.

objectivec
/// apiRegister the native api to be called for HTML
/// @param webApiName Native api names
/// @param handler Callback
- (BOOL)fat_registerWebApi:(NSString *)webApiName handler:(void (^)(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback))handler;

I have registered a method called js2AppFunction for the H5 in the applet here.

objectivec
    [[FATClient sharedClient] fat_registerWebApi:@"js2AppFunction" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) {
        NSString *name = param[@"name"];
//        id params = param[@"data"];
        if ([name isEqualToString:@"getLocation"]) {
            // Execute positioning logic

            // Return results to HTML
            NSDictionary *dict = @{@"errno":@"403", @"errmsg":@"No permission", @"result": @{@"address":@"Aerospace Technology Plaza, Nanshan District, Shenzhen, Guangdong Province"}};
            callback(FATExtensionCodeSuccess, dict);
        } else if ([name isEqualToString:@"getColor"]) {
            // Execute other logic

            // Return results to HTML
            NSDictionary *dict = @{@"r":@"110",@"g":@"150",@"b":@"150"};
            callback(FATExtensionCodeSuccess, dict);
        }
    }];

Referencing our bridge JSSDK file within H5, you can call the above registered method.

Example of calling the registered method from within HTML:

javascript
window.pz.miniProgram.callNativeAPI(
  'js2AppFunction',
  { name: 'getLocation' },
  result => {
    console.log(result)
  }
)

2. Native calls to the JS API

Similarly if the host App wants to call a method in the H5 loaded by the applet, it can use this API.

objectivec
/**
 Native calls to JS functions in HTML (applets running in the foreground)
 @param eventName Function Name
 @param paramString The function's parameter dictionary converted to json
 @param pageId webView ID, can not be passed, default call H5 function in the topmost page
 @param handler Callback result: error code is FATErrorCodeAppletNotFound, the applet running in the foreground was not found
 */
- (void)fat_callWebApi:(NSString *)eventName paramString:(NSString *)paramString pageId:(NSNumber *)pageId handler:(void (^)(id result, NSError *error))handler;

/**
 Native calls to JS functions in HTML (appletId specified by applet)
 @param eventName Function Name
 @param appletId Small program publishing process
 @param paramString The function's parameter dictionary converted to json
 @param pageId webView ID, can not be passed, default call H5 function in the topmost page
 @param handler Callback result: error code is FATErrorCodeAppletNotFound, the applet running in the foreground was not found
*/
- (void)fat_callWebApi:(NSString *)eventName applet:(NSString *)appletId paramString:(NSString *)paramString pageId:(NSNumber *)pageId handler:(void (^)(id result, NSError *error))handler;

First, reference our bridge JSSDK file within H5.

Then, register the method in HTML, for example, the method name is app2jsFunction.

javascript
window.pz.registNativeAPIHandler('app2jsFunction', function(res) {
  // app2jsFunction callback
})

Finally, the native side calls the following API to call JS functions in HTML:

objectivec
NSString *jsonParams = @""; //Here it should be the json string converted from the parameter dictionary.
NSNumber *pageId = @(1234); //Here is the pageId passed from the HTML
[[FATClient sharedClient] fat_callWebApi:@"app2jsFunction" paramString:jsonParams pageId:pageId handler:^(id result, NSError *error) {

}];

3. Registering native components

Due to limited resources, the implementation of native components such as livePusher and livePlayer may require the use of external third-party controls, which can then be registered as native components. We now support the registration of three native components: Camera, LivePlayer, and LivePusher.

3.1 Implementing custom native components

First, create the component view and implement its protocol methods.

.h

objectivec
#import <UIKit/UIKit.h>
#import <FinApplet/FATAppletNativeProtocol.h>

NS_ASSUME_NONNULL_BEGIN

@interface FATNativeView : UIView <FATAppletNativeViewProtocol>
@property (nonatomic, strong) NSNumber *nativeViewId;
@property (nonatomic, strong) NSString *type;

@end

@interface FATNativeCameraView : FATNativeView <FATAppletNativeCameraProtocol>

@end

@interface FATNativeLivePlayerView : FATNativeView <FATAppletNativeLivePlayerProtocol>

@end

@interface FATNativeLivePusherView : FATNativeView <FATAppletNativeLivePusherProtocol>

@end

NS_ASSUME_NONNULL_END

.m

objectivec
@implementation FATNativeView
+ (UIView *)onCreateView:(NSDictionary *)param {
    return [[self alloc] initWithParam:param];
}

- (instancetype)initWithParam:(NSDictionary *)param {
    CGRect frame = CGRectZero;
    NSDictionary *style = [param objectForKey:@"style"];
    if (style) {
        CGFloat x = [[style objectForKey:@"left"] floatValue];
        CGFloat y = [[style objectForKey:@"top"] floatValue];
        CGFloat height = [[style objectForKey:@"height"] floatValue];
        CGFloat width = [[style objectForKey:@"width"] floatValue];
        frame = CGRectMake(x, y, width, height);
    }
    self = [super initWithFrame:frame];
    if (self) {
        _type = param[@"type"];
        _nativeViewId = param[@"nativeViewId"];
    }
    return self;
}

- (void)onUpdateView:(NSDictionary *)param {
    NSDictionary *style = [param objectForKey:@"style"];
    if (style) {
        CGRect frame = CGRectZero;
        CGFloat x = [[style objectForKey:@"left"] floatValue];
        CGFloat y = [[style objectForKey:@"top"] floatValue];
        CGFloat height = [[style objectForKey:@"height"] floatValue];
        CGFloat width = [[style objectForKey:@"width"] floatValue];
        frame = CGRectMake(x, y, width, height);
        self.frame = frame;
    }
}

- (void)onDestroyView:(NSDictionary *)param {
    NSLog(@"Destroyed%@",param);
}

@end


@implementation FATNativeCameraView

- (void)setCameraZoom:(NSDictionary *)param success:(FATNativeCallback)callBack {

}

@end

@implementation FATNativeLivePlayerView


@end

@implementation FATNativeLivePusherView


@end

Then, set the component's view class

objectivec
[FATClient sharedClient].nativeViewManager.cameraClass = [FATNativeCameraView class];
[FATClient sharedClient].nativeViewManager.livePlayerClass = [FATNativeLivePlayerView class];
[FATClient sharedClient].nativeViewManager.livePusherClass = [FATNativeLivePusherView class];

3.2 Sending messages to components natively

The host App sends messages to the native component through the nativeViewManager.

objectivec
/// Send events to nativeView (applets running in the foreground)
/// @param eventName Event Name
/// @param nativeViewId native-view id
/// @param detail Event detail parameters
/// @param completion Completion callback: error code is FATErrorCodeAppletNotFound, the applet running in the foreground was not found
- (void)sendEvent:(NSString *)eventName nativeViewId:(NSNumber *)nativeViewId detail:(NSDictionary *)detail completion:(void (^)(id result, NSError *error))completion;

/// Send event to nativeView (appletId specified by applet)
/// @param eventName Event Name
/// @param appletId AppId of the applet, cannot be empty
/// @param nativeViewId native-view id
/// @param detail Event detail parameters
/// @param completion Completion callback: error code is FATErrorCodeForegroundAppletNotFound, appletId specified applet was not found
- (void)sendEvent:(NSString *)eventName applet:(NSString *)appletId nativeViewId:(NSNumber *)nativeViewId detail:(NSDictionary *)detail completion:(void (^)(id result, NSError *error))completion;

Sample Code

objectivec
[[FATClient sharedClient].nativeViewManager sendEvent:@"eventName" nativeViewId:@(1234) detail:@{} completion:^(id result, FATError *error) {

}];

3.3 Send global messages to applets natively

objectivec
/// Send global events (applets running in the foreground)
/// @param detail Event detail parameters
/// @param completion Completion callback: error code is FATErrorCodeAppletNotFound, the applet running in the foreground was not found
- (void)sendCustomEventWithDetail:(NSDictionary *)detail completion:(void (^)(id result, NSError *error))completion;

/// Send global events (applets running in the foreground)
/// @param detail Event detail parameters
/// @param appletId AppId of the applet, cannot be empty
/// @param completion Completion callback: error code is FATErrorCodeForegroundAppletNotFound, appletId specified applet was not found
- (void)sendCustomEventWithDetail:(NSDictionary *)detail applet:(NSString *)appletId completion:(void (^)(id result, NSError *error))completion;

Example code:

objectivec
[[FATClient sharedClient].nativeViewManager sendCustomEventWithDetail:@{} completion:^(id result, NSError *error) {
}];