Skip to content

API/Component Customization

1. Registering Custom APIs

If the mini progmini needs to call some capabilities provided by the host App, and the FinClip mini progmini SDK is not implemented or cannot be implemented, you can register a custom API to make the mini progmini 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 mini programs.
  2. a custom API registered for use by H5 loaded by the WebView component in the mini progmini.

1.1 Register the mini progmini asynchronous API

Registering functions for a custom asynchronous API

objective-c
/**
 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 finclipLogin here so that it can be used directly in the mini progmini.

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

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

Then, create the FinClipConf.js file in the root directory of the mini progmini, with the following sample configuration:

js
module.exports = {
  extApi: [
    {
      //General Interaction API
      name: "finclipLogin", //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 ft.loadExtApi

Finally, call the custom API in the mini progmini, sample code:

js
ft.finclipLogin({
  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 mini progmini sync API

Since 2.36.1, FinClip mini progmini SDK also supports registering custom synchronous APIs.

The functions for registering custom synchronous APIs are:

objective-c
/**
 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 mini progmini API here: 1).

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

objective-c
[[FATClient sharedClient] registerSyncExtensionApi:@"finclipTestSync" 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 FinClipConf.js file in the root directory of the mini progmini and add the sync api

js
module.exports = {
  extApi: [
    {
      //General Interaction API
      name: "finclipLogin", //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: "finclipTestSync",
      sync: true, // Whether it is synchronous api
      params: {
        name: "",
        title: "",
      },
    },
  ],
};

3). Call in the mini progmini

js
const res = ft.finclipTestSync({ name: "Zhang San", title: "Finclip" });
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 > FinClipConf.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 = ft.finclipTestSync({'name':'Zhang San'}), const res = ft.finclipTestSync({}), const res = ft. finclipTestSync() will all result in an error being reported and the event cannot be sent to the native. So the params in FinClipConf.js are better left out or declared as {}.

1.3 Register JS API

The web-view component can be used in the mini progmini 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.

objective-c
/// 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 mini progmini here.

objective-c
    [[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.ft.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.

objective-c
/**
 Native calls to JS functions in HTML (mini programs 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 mini progmini)
 @param eventName Function Name
 @param appletId mini 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.ft.registNativeAPIHandler("app2jsFunction", function (res) {
  // app2jsFunction callback
});

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

objective-c
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

objective-c
#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

objective-c
@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

objective-c
[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.

objective-c
/// Send events to nativeView (mini programs 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 mini progmini 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 mini progmini)
/// @param eventName Event Name
/// @param appletId AppId of the mini progmini, cannot be empty
/// @param nativeViewId native-view id
/// @param detail Event detail parameters
/// @param completion Completion callback: error code is FATErrorCodeForegroundAppletNotFound, appletId specified mini progmini 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

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

}];

3.3 Send global messages to mini programs natively

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

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

Example code:

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