Appearance
Android SDK FAQs
Common Issues with Android
1. Common Issues during Integration
1.1 What are the minimum environment configurations required for integrating the SDK?
Answer: The SDK requires an Android SDK version of 19 (Android 4.4) or higher.
1.2 What are the specific steps for integration?
Answer: Please search with th SDK Integration Documentation
1.3 Do I need to configure obfuscation rules for integrating the SDK?
Answer: Yes, obfuscation rules need to be configured as follows:
bash
-keep class com.finogeeks.** {*;}
1.4 What mandatory parameters must be configured when initializing the SDK?
Answer: At a minimum, you need to provide the SDK Key, SDK Secret, server address, server API request route prefix, and encryption method by passing them through the FinAppConfig
instance.
Prior to version 2.13.102
, the SDK only supports configuring a single server information, allowing only a single Mini Program to be opened in a single environment as follows:
java
FinAppConfig config = new FinAppConfig.Builder()
.setSdkKey(BuildConfig.SDK_KEY) // SDK Key, issued by the platform after successful cooperation with the application
.setSdkSecret(BuildConfig.APP_SECRET) // SDK Secret, issued by the platform after successful cooperation with the application
.setApiUrl(BuildConfig.API_URL) // Server address
.setApiPrefix(BuildConfig.API_PREFIX) // Server interface request route prefix
.setEncryptionType(ENCRYPTION_TYPE_SM) // Encryption method: National encryption (SM), md5: MD5
.build();
Starting from version 2.13.102
, the SDK supports configuring multiple server information, allowing multiple Mini Programs to be opened from different environments as follows:
java
// Collection of server information
List<FinStoreConfig> storeConfigs = new ArrayList<>();
// Information for Server 1
FinStoreConfig storeConfig1 = new FinStoreConfig(
"SDK Key Info", // SDK Key
"SDK Secret Info", // SDK Secret
"Server 1 Address", // Server address
"Server 1 Data Reporting Address", // Data reporting server address
"/api/v1/mop/", // Server interface request route prefix
"",
"Encryption Method" // Encryption method: National encryption (SM), md5: MD5
);
storeConfigs.add(storeConfig1);
// Information for Server 2
FinStoreConfig storeConfig2 = new FinStoreConfig(
"SDK Key Info", // SDK Key
"SDK Secret Info", // SDK Secret
"Server 2 Address", // Server address
"Server 2 Data Reporting Address", // Data reporting server address
"/api/v1/mop/", // Server interface request route prefix
"",
"Encryption Method" // Encryption method: National encryption (SM), md5: MD5
);
storeConfigs.add(storeConfig2);
FinAppConfig config = new FinAppConfig.Builder()
.setFinStoreConfigs(storeConfigs) // Collection of server information
.build();
1.5 What optional parameters can be configured when initializing the SDK?
Answer: Besides the mandatory parameters mentioned above, other parameters can be chosen based on needs, including UI configurations, and Canary Release rules configurations.
UI configuration is as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Whether to hide the close button at the top right corner
uiConfig.setHideNavigationBarCloseButton(false);
// Whether to hide the "Forward" button in the "More" menu
uiConfig.setHideForwardMenu(false);
// Whether to hide "Feedback and Complaints" in the More menu
uiConfig.setHideFeedbackAndComplaints(false);
// Whether to hide "Back to Home" button in the navigation bar
uiConfig.setHideBackHome(false);
// Whether to always show the back button when the navigation bar is the default one
uiConfig.setAlwaysShowBackInDefaultNavigationBar(false);
// Text appearance style for the navigation bar title
uiConfig.setNavigationBarTitleTextAppearance(R.style.TextAppearance_AppCompat);
// Gravity for navigation bar title relative to parent control
uiConfig.setNavigationBarTitleTextLayoutGravity(Gravity.CENTER);
// Whether to clear the navigation bar button background
uiConfig.setClearNavigationBarNavButtonBackground(true);
// "More" menu style
uiConfig.setMoreMenuStyle(UIConfig.MORE_MENU_DEFAULT);
// Capsule button configuration
uiConfig.setCapsuleConfig(new CapsuleConfig());
APM data reporting extended information is as follows:
java
// APM data reporting extended information
Map<String, Object> apmExtendInfo = new HashMap<>();
apmExtendInfo.put("key1", "value1");
apmExtendInfo.put("key2", "value2");
Optional parameters can be passed to the SDK together with the mandatory parameters via the FinAppConfig
instance, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Whether to hide the close button at the top right corner
uiConfig.setHideNavigationBarCloseButton(false);
// Whether to hide the "Forward" button in the "More" menu
uiConfig.setHideForwardMenu(false);
// Whether to hide the "Settings" button in the "More" menu
uiConfig.setHideSettingMenu(false);
// Whether to hide "Feedback and Complaints" in the More menu
uiConfig.setHideFeedbackAndComplaints(false);
// Whether to hide "Back to Home" button in the navigation bar
uiConfig.setHideBackHome(false);
// Whether to always show the back button when the navigation bar is the default one
uiConfig.setAlwaysShowBackInDefaultNavigationBar(false);
// Text appearance style for the navigation bar title
uiConfig.setNavigationBarTitleTextAppearance(R.style.TextAppearance_AppCompat);
// Gravity for navigation bar title relative to parent control
uiConfig.setNavigationBarTitleTextLayoutGravity(Gravity.CENTER);
// Whether to clear the navigation bar button background
uiConfig.setClearNavigationBarNavButtonBackground(true);
// "More" menu style
uiConfig.setMoreMenuStyle(UIConfig.MORE_MENU_DEFAULT);
// Capsule button configuration
uiConfig.setCapsuleConfig(new CapsuleConfig());
// APM data reporting extended information
Map<String, Object> apmExtendInfo = new HashMap<>();
apmExtendInfo.put("key1", "value1");
apmExtendInfo.put("key2", "value2");
// Domains for which cookies need to be removed
List<String> needToRemoveCookiesDomains = new ArrayList<>();
needToRemoveCookiesDomains.add("https://aaa.bbb.ccc");
FinAppConfig config = new FinAppConfig.Builder()
.setSdkKey(BuildConfig.SDK_KEY) // SDK Key, issued by the platform after successful cooperation with the application
.setSdkSecret(BuildConfig.APP_SECRET) // SDK Secret, issued by the platform after successful cooperation with the application
.setApiUrl(BuildConfig.API_URL) // Server address
.setApiPrefix(BuildConfig.API_PREFIX) // Server API request route prefix
.setDebugMode(BuildConfig.DEBUG) // Whether the application is currently in debug mode
.setUiConfig(uiConfig) // UI Configuration
.setApmExtendInfo(apmExtendInfo) // APM data reporting extended information
.setEncryptionType(ENCRYPTION_TYPE_SM) // Encryption method: National encryption (SM), md5: MD5
.setDisableRequestPermissions(true) // Whether to forbid runtime permission request, default is not forbidden
.setAppletAutoAuthorize(false) // Whether to enable automatic granting of Mini Program Scope permission, default is not enabled
.setNeedToRemoveCookiesDomains(needToRemoveCookiesDomains) // Domains for which cookies need to be removed
.setDisableTbs(true) // Whether to disable the Tbs SDK, default is not disabled
.setCustomWebViewUserAgent("aaa/111; bbb") // Custom WebView UserAgent
.setAppletIntervalUpdateLimit(6) // Limit for scheduled bulk updates of Mini Programs
.setForegroundServiceConfig(new FinAppConfig.ForegroundServiceConfig(true, R.drawable.ic_launcher, "Mini Program is running", "")) // Whether to start a foreground service when the Mini Program is running in the front
.setBindAppletWithMainProcess(true) // Binding Mini Program with app process; if the App is killed, whether to close the Mini Program synchronously, default is false
.setWebViewMixedContentMode(MIXED_CONTENT_ALWAYS_ALLOW) // Set WebView mixed content mode
.setAppletText("X Application") // Replace the text "Mini Program" with "X Application" in the SDK
.setEnableApmDataCompression(true) // Whether to compress data during reporting, default is not compressed
.setDisableGetSuperviseInfo(true) // Whether to forbid calling the API to get regulatory information for Mini Programs, default is not forbidden
.setUserId("User ID") // Set User ID
.build();
1.6 Are there any special considerations when initializing the SDK?
Answer: The SDK adopts a multi-process mechanism; each Mini Program runs in an independent process, meaning one Mini Program corresponds to one process. A critical point to keep in mind during SDK initialization is that no initialization operations should be performed in the Mini Program process, even initializing the Mini Program SDK is unnecessary in the Mini Program process.
For instance, if the application uses some third-party libraries that require initialization at startup, you should only initialize those libraries when the current process is the host process. No initialization of those libraries is needed in the Mini Program process.
Thus, before initializing the SDK, it's essential to determine which process is currently running. If it's the Mini Program process and you do not need to handle inter-process call interfaces or register APIs in the Mini Program process, no actions are required:
java
/**
* Application's {@link android.app.Application}
*/
public class AppletApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
// Code to check if it's the Mini Program process should be placed at the very beginning
if (FinAppClient.INSTANCE.isFinAppProcess(this)) {
return;
}
// Other code goes here
}
}
1.7 How can I resolve dependency conflicts encountered during integration?
Answer: The Android Mini Program SDK has dependencies on the following third-party libraries:
groovy
// appcompat-v7
implementation "com.android.support:appcompat-v7:23.0.0"
// support-v4
implementation "com.android.support:support-v4:23.0.0"
// RecyclerView
implementation "com.android.support:recyclerview-v7:23.2.0"
// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.61"
// Gson
implementation "com.google.code.gson:gson:2.9.0"
// zxing
implementation "com.google.zxing:core:3.3.0"
implementation "com.google.zxing:android-core:3.3.0"
// SdkCore
implementation "com.finogeeks.finochat.sdk:sdkcore:2.15.1"
The SDK dependencies are managed using Gradle. If both the app and the SDK depend on the same library, Gradle will automatically handle conflicts by using the library version with the higher number.
If there is a conflict between the libraries that are dependencies of the app (included via JAR or source code) and those in the SDK, the specific SDK dependency can be excluded using the exclude
command.
For example:
groovy
implementation('com.finogeeks.lib:finapplet:2.21.1') {
exclude group: "com.tecent.smtt"
}
Additionally, it is still recommended to manage dependencies using Gradle for better compatibility.
1.7.1 What to do if there are duplicate classes in zxing:android-core?
Answer: The SDK uses the zxing:android-core library, and due to naming conflicts with the CameraConfigurationUtils
class in the zxing-android-embedded library, some users may encounter class name conflicts when using the zxing-android-embedded library. In this case, you can use the exclude
command to remove the dependency.
For example:
groovy
implementation('com.finogeeks.lib:finapplet:2.21.1') {
exclude group: "com.google.zxing" , module:"android-core"
}
2. Common Issues during Usage
2.1 How to launch a Mini Program?
- To launch a Mini Program without any start parameters, use the
IAppletApiManager
interface'sstartApplet(context: Context, appId: String)
method as follows:
java
FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, "appId");
Or:
java
FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, IFinAppletRequest);
- To launch a Mini Program with start parameters, use the
IAppletApiManager
interface'sstartApplet(context: Context, appId: String, startParams: Map<String, String>)
method as follows:
java
Map<String, String> params = new HashMap<>();
// path refers to Mini Program page path
params.put("path", "/pages/index/index");
// query refers to start parameters in the format of "key1=value1&key2=value2 ..."
params.put("query", "aaa=test&bbb=123");
FinAppClient.INSTANCE.getAppletApiManager().startApplet(this, "appId", params);
2.2 After launching multiple Mini Programs from the host app, why do I see multiple Mini Program tasks in the Android system's recent tasks list along with the host application?
Answer: Because the Android Mini Program SDK implements a multi-process mechanism, the host application runs in one process while each Mini Program runs in its own independent process. Consequently, in the Android system's recent tasks list, different processes will be displayed separately, resulting in multiple Mini Programs being visible.
This is similar to current mainstream Mini Programs, such as those from WeChat and Baidu's Android version.
2.3 Do Mini Program APIs support extensions? In other words, besides the standard APIs provided within the SDK, can Mini Programs call their own APIs? If so, how can this be implemented?
Answer: Mini Program APIs support extensions. The SDK allows registering custom Mini Program APIs, which can then be called just like the standard APIs provided by the SDK.
The specific implementation steps are as follows:
- Implement the custom Mini Program API.
TheIApi
interface declares the two core methods that need to be implemented:apis();
andinvoke(String event, JSONObject param, ICallback callback);
. The corresponding code is as follows:
java
/**
* Mini Program API interface; APIs that implement functionality need to implement this interface
*/
public interface IApi extends ILifecycle {
/**
* @return Array of callable API names
*/
String[] apis();
/**
* This method is triggered when an API call is received, where specific business logic is implemented
*
* @param event Event name, which is the API name
* @param param Parameters
* @param callback Callback interface
*/
void invoke(String event, JSONObject param, ICallback callback);
}
To implement a custom interface, create a class that extends AbsApi
(a subclass of IApi
) and override the apis()
and invoke()
methods. The apis()
method should return an array of all callable API names, establishing the APIs that need to be implemented.
The invoke()
method will be triggered when the Mini Program calls the API, where the event
parameter represents the API name, param
refers to parameters corresponding to the API, and callback
is used for returning data back to the Mini Program after executing the call logic.
For example, we can define a custom Mini Program interface to facilitate simple page navigation as follows:
java
/**
* Custom Mini Program interface to achieve simple page navigation
*/
public class ApiOpenPage extends AbsApi {
private static final String API_NAME_OPEN_PAGE = "openPage";
private Context mContext;
public ApiOpenPage(Context context) {
mContext = context;
}
/**
* @return Array of callable API names
*/
@Override
public String[] apis() {
return new String[]{API_NAME_OPEN_PAGE};
}
/**
* This method is triggered when an API call is received, implement the specific business logic here
*
* @param event Event name representing the API name
* @param param Parameters
* @param callback Callback interface
*/
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
if (API_NAME_OPEN_PAGE.equals(event)) {
String url = param.optString("url");
if (!TextUtils.isEmpty(url)) {
Intent intent = new Intent();
intent.setClass(mContext, SecondActivity.class);
if (!(mContext instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
mContext.startActivity(intent);
callback.onSuccess(null);
} else {
callback.onFail();
}
}
}
}
- Register the custom Mini Program API.
The custom API can be registered by calling theregisterApi
method of theIExtensionApiManager
interface, as follows:
java
FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new ApiOpenPage(context));
If multiple interfaces need to be registered at once, you can also call registerApis
, passing in a collection of interfaces.
- Add extension interface configuration in the Mini Program project.
After the SDK registers the custom Mini Program APIs, aFinClipConf.js
file must be created in the root directory of the Mini Program project to configure the corresponding custom interfaces. A sample configuration for reference:
javascript
module.exports = {
extApi: [
{
name: "openPage", // Extended interface name
params: {
// Parameters for the extended interface, can include only required parameters
url: "",
title: "",
description: "",
},
},
],
};
- Call the registered APIs within the Mini Program.
2.4 Can a web page loaded within a Mini Program call native code?
Answer: Yes, a web page within a Mini Program can invoke native code. The JSSDK provides a series of interfaces to facilitate native code invocation from within the web page.
2.5 Does the JSSDK interface support extensions? Can Mini Programs invoke their own provided interfaces within the web page? If so, how can this be achieved?
Answer: Yes, the JSSDK interface allows for extensions. The SDK permits registering custom JSSDK interfaces that can be called in the same way as the standard interfaces provided within the JSSDK.
The specific implementation steps resemble those for creating custom Mini Program APIs:
Implement the custom JSSDK interface.
This step is identical to implementing a custom Mini Program API by extendingAbsApi
and overriding theapis()
andinvoke()
methods.Register the custom JSSDK interface.
This can be done via theIExtensionWebApiManager
interface'sregisterApi
method, as follows:
java
FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new ApiOpenPage(context));
If multiple interfaces need to be registered at once, you can also use registerApis
, passing in a collection of interfaces.
For details, please search with Register Mini Program WebView Component APIs.
2.6 When I redirect to other pages of the host App via the custom interface's invoke()
method and perform a series of operations, pressing the system back button takes me back to the host App's page that launched the Mini Program instead of returning to the Mini Program. Why does this happen?
1. Reason:
The step of redirecting to another page of the host App is carried out using the Context instance from the host App to launch the Activity without placing the Activity into a new task stack.
The Android Mini Program SDK employs a multi-process architecture, meaning the Mini Program and host App operate in different processes and thus belong to different task stacks. When the Mini Program navigates to a page in the host App, the newly opened page is added to the existing task stack of the host App, resulting in sequential closure of the host App's pages when returning from the page.
2. Solution:
Option 1 (Recommended):
Use ICallback
's startActivity
or startActivityForResult
to navigate to other pages in the host App.
This is the preferred approach because it opens the new host App Activity within the task stack of the Mini Program, performing the Activity's entry and exit in the same task stack without task stack switching.
More importantly, if you need to start an Activity using `startActivityForResult` and retrieve returned data upon page return, this is the only option where the custom interface's `onActivityResult` will be executed, allowing for the retrieval of the returned data.
Example for this option:
java
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
Intent intent = new Intent();
intent.setClass(mContext, SecondActivity.class);
callback.startActivityForResult(intent, 100);
}
Option 2 (Not Recommended):
If it is essential to utilize the Context instance from the host App to initiate the Activity, you will need to set the "support multi-task stack" and "open new task stack" flags for the Intent. This allows for a new task stack to be opened in the host App's process where the new page will be sequentially pushed onto this new task stack. Once all operations on the native page are completed, exiting the native page results in popping the pages from this new task stack, thus returning to the task stack of the Mini Program process.
Therefore, in the custom interface's invoke()
method, if you need to redirect to different pages in the native application and expect to return to the Mini Program after closing those pages, it is advisable to add both Intent.FLAG_ACTIVITY_MULTIPLE_TASK
and FLAG_ACTIVITY_NEW_TASK
to the Intent
object during navigation, as shown below:
java
Intent intent = new Intent();
intent.setClass(context, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); // Context is the instance from the host App
Using this option means that calling startActivityForResult
when initiating an Activity won’t trigger onActivityResult
, which is why this approach is not recommended.
2.7 Can native code call JavaScript functions in the web page?
Answer: Yes, the SDK allows native code to call JavaScript functions. This can be accomplished through the IAppletApiManager
interface's callJS
method:
java
JSONObject funcParams = new JSONObject();
try {
funcParams.put("param1", "value1");
funcParams.put("param2", "value2");
FinAppClient.INSTANCE.getAppletApiManager().callJS(
"appId",
"funcName",
funcParams.toString(),
-1,
new FinCallback<String>() {
@Override
public void onSuccess(String result) {
Log.d(TAG, "callJS onSuccess : " + result);
}
@Override
public void onError(int code, String error) {
Log.d(TAG, "callJS onError : " + code + ", " + error);
}
@Override
public void onProgress(int status, String info) {
}
});
} catch (JSONException e) {
e.printStackTrace();
}
2.8 How to set the activity transition animations in Mini Programs?
Answer: You can set the transition animations for activities in Mini Programs through the IAppletApiManager
interface's setActivityTransitionAnim
method as follows:
java
FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(SlideFromRightToLeftAnim.INSTANCE);
Currently, five types of animations are available for setting:
- NoneAnim: No animation;
- SlideFromLeftToRightAnim: Slide animation - Slide in from left and out to right;
- SlideFromRightToLeftAnim: Slide animation - Slide in from right and out to left;
- SlideFromTopToBottomAnim: Slide animation - Slide in from top and out to bottom;
- SlideFromBottomToTopAnim: Slide animation - Slide in from bottom and out to top.
2.9 How to Share Mini Programs to WeChat and Other Supported Platforms?
Answer: To implement the mini program sharing feature, the overall approach involves first acquiring the relevant information needed for sharing the mini program, then converting the retrieved information into parameters for the sharing interface, and finally calling the sharing interface to share the mini program to the corresponding platform. There are two main implementation strategies:
Implement the abstract business callback interface
IAppletHandler
with theshareAppMessage
method, and pass theIAppletHandler
instance to the SDK.When the "Forward" option is selected from the mini program's more menu, the
shareAppMessage
method of theIAppletHandler
instance will be called. This method contains parameters such as mini program information and screenshots. Once these parameters are retrieved, the third-party sharing SDK can be invoked to perform the sharing.The
shareAppMessage
method is defined as follows:kotlin/** * Share the mini program * * @param appInfo Mini program information as a JSON string, including mini program ID, name, icon, user ID, and forwarding data content. * The content format of [appInfo] is as follows: * { * "appTitle": "FinClip Mini Program", * "appAvatar": "https:\/\/www.finogeeks.club\/statics\/images\/swan_mini\/swan_logo.png", * "appId": "5df36b3f687c5c00013e9fd1", * "appType": "trial", * "userId": "finogeeks", * "cryptInfo": "<encrypted information>", * "params": { * "title": "apt-test-tweet - Interface Test Published!", * "desc": "Your service expert by your side", * "imageUrl": "finfile:\/\/temp_image.png", * "path": "pages\/tweet\/tweet-detail.html?fcid=%40staff_staff1%3A000000.finogeeks.com&timelineId=<timelineId>&shareId=<shareId>", * "appInfo": { * "weixin": { * "path": "\/studio\/pages\/tweet\/tweet-detail", * "query": { * "fcid": "@staff_staff1:000000.finogeeks.com", * "timelineId": "<timelineId>" * } * } * } * } * } * Explanation of fields in [appInfo]: * - appId: Mini program ID * - appTitle: Mini program name * - appAvatar: Mini program avatar * - appType: Mini program type; where 'trial' indicates a trial version, 'temporary' indicates a temporary version, 'review' indicates a review version, 'release' indicates a production version, and 'development' indicates a development version * - userId: User ID * - cryptInfo: Mini program encrypted information * - params: Other parameters passed through by the mini program * * @param bitmap Cover image of the mini program. If [appInfo].params.imageUrl field is an HTTP or HTTPS link, the cover image will be taken from that URL. Otherwise, the cover image will be the [bitmap]. * @param callback The callback for sharing results. */ fun shareAppMessage(appInfo: String, bitmap: Bitmap?, callback: IAppletCallback)
The
IAppletHandler
instance can be passed using theIAppletApiManager
methodsetAppletHandler(appletHandler: IAppletHandler)
, as demonstrated below:javaFinAppClient.INSTANCE.getAppletApiManager().setAppletHandler(new IAppletHandler() { @Override public void shareAppMessage(@NotNull String appInfo, @org.jetbrains.annotations.Nullable Bitmap bitmap, @NotNull IAppletCallback callback) { // Implement the logic for sharing the mini program …………………………………………………… …………………………………………………… } });
Implement a custom interface. In the
invoke
method of the custom interface, receive the parameters passed from the mini program, and then call the third-party sharing SDK to perform the sharing of the mini program.
2.10 How to Inject Your Own Menu Items into the "More" Menu?
Answer: Similar to sharing the mini program through the abstract business callback interface IAppletHandler
, injecting menu items into the "More" menu is also done via the IAppletHandler
. The IAppletHandler
will provide the host app with the interface method getRegisteredMoreMenuItems
for acquiring the injected menu items and the method onRegisteredMoreMenuItemClicked
for handling clicks on the injected menu items, allowing the host app to implement the specific business logic.
The getRegisteredMoreMenuItems
and onRegisteredMoreMenuItemClicked
methods are defined as follows:
kotlin
/**
* Get registered "More" menu items
*
* @param appId Mini program ID
* @return Registered "More" menu items
*/
fun getRegisteredMoreMenuItems(appId: String): List<MoreMenuItem>?
/**
* Registered "More" menu item clicked
*
* @param appId Mini program ID
* @param path Mini program page path
* @param menuItemId The ID of the clicked menu item
* @param appInfo Mini program information, which is a JSON string, including mini program ID, name, icon, user ID, forwarding data content, etc.
* The content format of [appInfo] is as follows:
* {
* "appTitle": "FinClip Mini Program",
* "appAvatar": "https:\/\/www.finogeeks.club\/statics\/images\/swan_mini\/swan_logo.png",
* "appId": "5df36b3f687c5c00013e9fd1",
* "appType": "trial",
* "userId": "finogeeks",
* "cryptInfo": "<encrypted information>",
* "params": {
* "title": "apt-test-tweet - Interface Test Published!",
* "desc": "Your service expert by your side",
* "imageUrl": "finfile:\/\/temp_image.png",
* "path": "pages\/tweet\/tweet-detail.html?fcid=%40staff_staff1%3A000000.finogeeks.com&timelineId=<timelineId>&shareId=<shareId>",
* "appInfo": {
* "weixin": {
* "path": "\/studio\/pages\/tweet\/tweet-detail",
* "query": {
* "fcid": "@staff_staff1:000000.finogeeks.com",
* "timelineId": "<timelineId>"
* }
* }
* }
* }
* }
* Explanation of fields in [appInfo]:
* - appId: Mini program ID
* - appTitle: Mini program name
* - appAvatar: Mini program avatar
* - appType: Mini program type; where 'trial' indicates a trial version, 'temporary' indicates a temporary version, 'review' indicates a review version, 'release' indicates a production version, and 'development' indicates a development version
* - userId: User ID
* - cryptInfo: Mini program encrypted information
* - params: Other parameters passed through by the mini program
*
* @param bitmap Cover image of the mini program. If [appInfo].params.imageUrl field is an HTTP or HTTPS link, the cover image will be taken from that URL. Otherwise, the cover image will be the [bitmap].
* @param callback Result callback.
*/
fun onRegisteredMoreMenuItemClicked(appId: String, path: String, menuItemId: String, appInfo: String?, bitmap: Bitmap?, callback: IAppletCallback)
Similarly, the IAppletHandler
instance must be provided through the IAppletApiManager
method setAppletHandler(appletHandler: IAppletHandler)
.
An example implementation of the getRegisteredMoreMenuItems
and onRegisteredMoreMenuItemClicked
methods is provided below:
java
/**
* Implementation class of {@link IAppletHandler}, used to implement some business scenarios, such as registering "More" menu items, sharing mini programs, etc.
*/
public class AppletHandler implements IAppletHandler {
@NonNull
private Context mContext;
private AppletHandler() {
}
public AppletHandler(@NonNull Context context) {
this.mContext = context;
}
@Nullable
@Override
public List<MoreMenuItem> getRegisteredMoreMenuItems(@NotNull String appId) {
List<MoreMenuItem> items = new ArrayList<>();
MoreMenuItem item0 = new MoreMenuItem("WXShareAPPFriends", "WeChat Friends", MoreMenuType.ON_MINI_PROGRAM);
items.add(item0);
MoreMenuItem item1 = new MoreMenuItem("WXShareAPPMoments", "WeChat Moments", MoreMenuType.ON_MINI_PROGRAM, true);
items.add(item1);
MoreMenuItem item2 = new MoreMenuItem("ShareSinaWeibo", "Sina Weibo", MoreMenuType.ON_MINI_PROGRAM);
items.add(item2);
MoreMenuItem item3 = new MoreMenuItem("ShareQQFriends", "QQ", MoreMenuType.ON_MINI_PROGRAM);
items.add(item3);
MoreMenuItem item4 = new MoreMenuItem("ShareDingDing", "DingTalk", MoreMenuType.ON_MINI_PROGRAM);
items.add(item4);
MoreMenuItem item5 = new MoreMenuItem("ShareLinks", "Title as per backend configuration", MoreMenuType.ON_MINI_PROGRAM);
items.add(item5);
MoreMenuItem item6 = new MoreMenuItem("SharePicture", "Share Picture", MoreMenuType.ON_MINI_PROGRAM);
items.add(item6);
MoreMenuItem item7 = new MoreMenuItem("Restart", "Restart", MoreMenuType.COMMON);
items.add(item7);
MoreMenuItem item8 = new MoreMenuItem("Desktop", "Desktop", MoreMenuType.COMMON);
items.add(item8);
return items;
}
@Override
public void onRegisteredMoreMenuItemClicked(@NotNull String appId, @NotNull String path, @NotNull String menuItemId, @Nullable String appInfo, @Nullable Bitmap bitmap, @NotNull IAppletCallback callback) {
Toast.makeText(mContext, "Menu item " + menuItemId + " of the " + path + " page of mini program " + appId + " was clicked. appInfo: " + appInfo + " bitmap: " + bitmap, Toast.LENGTH_SHORT).show();
callback.onSuccess(null);
}
}
The MoreMenuItem
is a data class representing a menu item, as shown below:
kotlin
/**
* More menu item
*
* @param id Menu item ID
* @param title Menu item title
* @param image Menu item icon URL
* @param icon Menu item icon resource ID
* @param type Menu item type
* @param isEnable Whether the menu item is enabled
*/
data class MoreMenuItem(val id: String,
val title: String,
val image: String,
@DrawableRes val icon: Int,
val type: MoreMenuType = MoreMenuType.COMMON,
val isEnable: Boolean = true) {
/**
* Constructor
* @param id Menu item ID
* @param title Menu item title
* @param type Menu item type: [MoreMenuType.COMMON] or [MoreMenuType.ON_MINI_PROGRAM]
*/
constructor(id: String, title: String, type: MoreMenuType) : this(id, title, "", -1, type, true)
}
MoreMenuType
is an enumeration class defined as follows:
kotlin
/**
* More menu types
* [COMMON] indicates a normal menu type that does not require interaction with the mini program.
* [ON_MINI_PROGRAM] indicates a menu type that requires interaction with the mini program, such as sharing a mini program button, which may need to retrieve some data from the mini program when clicked.
*/
enum class MoreMenuType {
COMMON, ON_MINI_PROGRAM
}
2.11 How to capture a screenshot of the current page of the Mini Program?
Answer: You can search with Get Mini Program Page Screenshot.
2.12 How to hide the "Forward" button in the More menu?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Hide the "Forward" button in the "More" menu
uiConfig.setHideForwardMenu(true);
2.13 How to hide the "Settings" button in the More menu?
Answer: The "Settings" menu displays the Scope permissions of each Mini Program. To hide the "Settings" entry, configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Hide the "Settings" button in the "More" menu
uiConfig.setHideSettingMenu(true);
2.14 How to hide the "Return to Home" button in the More menu?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Hide the "Return to Home" menu entry in the "More" menu
uiConfig.setHideBackHome(true);
Note:
The "Return to Home" button in the More menu has been deprecated since version 2.36.1, and this configuration now controls the "Return to Home" button on the navigation bar.
2.15 How to hide the "Feedback and Complaints" entry in the More menu?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Hide "Feedback and Complaints" in the More menu
uiConfig.setHideFeedbackAndComplaints(true);
2.16 How to display the "Share" button in the More menu?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Show the "Share" button in the More menu
// Default value is true (hidden)
uiConfig.setHideShareAppletMenu(false);
2.17 How to hide the close button in the navigation bar?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Hide the close button in the top right corner
uiConfig.setHideNavigationBarCloseButton(true);
2.18 When the navigation bar is of default style, how to ensure the back button is visible on the home page?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Always show the back button when the navigation bar is the default style
uiConfig.setAlwaysShowBackInDefaultNavigationBar(false);
2.19 How to configure Canary Release rules?
Answer: Similar to sharing the Mini Program through the abstract business callback interface IAppletHandler
, the injection of configuration parameters for Canary Releases is also achieved through IAppletHandler
. The IAppletHandler
will callback the host app to obtain the interface method for acquiring Canary Release configuration parameters: getGrayAppletVersionConfigs
, which is then implemented by the host app with specific business logic.
getGrayAppletVersionConfigs
is as follows:
kotlin
/**
* Get Canary Release configuration parameters
*
* @param appId Mini Program ID
* @return Canary Release configuration parameters
*/
fun getGrayAppletVersionConfigs(appId: String): List<GrayAppletVersionConfig>?
Similarly, the IAppletHandler
instance needs to be passed by calling the setAppletHandler(appletHandler: IAppletHandler)
method of IAppletApiManager
.
Note
Since FinClip Mini Program does not provide a user system, when creating gray rules and selecting "Release to Specified Users", the user information from the app must be passed to the Mini Program through a custom API. Only at this time can the Mini Program publish to specified users (when passing user ID via custom API, the default rule ID is xUserId
).
2.20 How to implement a custom navigation bar?
Answer: Currently, three styles of navigation bars are provided:
- Default style (default);
- Custom style that retains only the "More Close" button (custom);
- Custom style that hides all native navigation bar elements and does not retain the "More Close" button (hide).
By default, both the navigationStyle
of the page
and the window
in the Mini Program are set to default. If developers wish to customize the navigation bar style, they can configure the navigationStyle
of either the page
or the window
.
2.21 Does it support disabling the SDK's proactive permission requests?
Answer: Yes.
If the host app wishes to manage all SDK permission requests itself, not wanting the SDK to proactively request permissions when needed, this can be achieved by configuring parameters during the SDK initialization, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setDisableRequestPermissions(true) // Disable SDK from initiating runtime permission requests
.build();
2.22 Does it support configuring automatic granting of Scope permissions when the Mini Program requests them?
Answer: Yes.
Scope permissions can be viewed, enabled, or disabled in the Mini Program's "More"-"Settings." By default, every time a Mini Program requests Scope permissions, a dialog box will pop up asking the user for permission. If the SDK wishes to automatically grant Scope permissions without prompting the user, this can be configured during SDK initialization, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setAppletAutoAuthorize(true) // Automatically grant Scope permissions
.build();
2.23 How to adjust the title text style of the navigation bar?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Navigation bar title text style
uiConfig.setNavigationBarTitleTextAppearance(R.style.TextAppearance_AppCompat);
2.24 How to center the navigation bar title?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Gravity of navigation bar title relative to parent view
uiConfig.setNavigationBarTitleTextLayoutGravity(Gravity.CENTER);
2.25 How to remove the background animation when the navigation bar back button is pressed?
Answer: Configure it via UI configuration options when initializing the SDK, as follows:
java
// UI Configuration
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
// Clear the background of navigation bar navigation buttons
uiConfig.setClearNavigationBarNavButtonBackground(true);
2.26 Does the Mini Program support switching between portrait and landscape modes?
Answer: Yes.
The Mini Program supports switching freely between portrait and landscape modes. The screen rotation settings for the Mini Program can be configured globally in the app.json
file under the window
, or individually in each page's .json
file.
Global configuration in
app.json
:json{ "window": { "pageOrientation": "auto" // auto: freely switch between portrait and landscape, portrait: portrait mode, landscape: landscape mode } }
Individual configuration in each page's
.json
file:json{ "pageOrientation": "auto" // auto: freely switch between portrait and landscape, portrait: portrait mode, landscape: landscape mode }
The page configuration will override the same settings in
app.json
for the current page.
2.27 How to disable TBS SDK?
Answer: You can achieve this by configuring the parameters during SDK initialization, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setDisableTbs(true) // Set whether to disable Tbs SDK
.build();
2.28 How to set the number of Mini Programs for scheduled batch updates?
Answer: You can achieve this by configuring the parameters during SDK initialization, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setAppletIntervalUpdateLimit(3) // Set the number of Mini Programs for scheduled batch updates
.build();
2.29 How to set the number of Mini Programs that can be opened simultaneously?
Answer: You can achieve this by configuring the parameters during SDK initialization, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setMaxRunningApplet(3) // Set the number of Mini Programs that can be opened simultaneously
.build();
2.30 Does the Mini Program support controlling the visibility of the "More" button in the upper right corner?
Answer: Yes.
You can achieve this by configuring the navigationBarHideMoreButton
property, which can be set globally in the app.json
file under the window
, or individually in each page's .json
file.
Global configuration in
app.json
:json{ "window": { "navigationBarHideMoreButton": true // true: hide the "More" button in the upper right corner; false: show the "More" button; default is false. } }
Individual configuration in each page's
.json
file:json{ "navigationBarHideMoreButton": true // true: hide the "More" button in the upper right corner; false: show the "More" button; default is false. }
2.31 Can the Mini Program control the visibility of the close button in the upper right corner?
Answer: Yes. You can achieve this by configuring the navigationBarHideCloseButton
property, which can be set globally in the app.json
file under the window
, or individually in each page's .json
file.
Global configuration in
app.json
:json{ "window": { "navigationBarHideCloseButton": true // true: hide the close button in the upper right corner; false: show the close button; default is false. } }
Individual configuration in each page's
.json
file:json{ "navigationBarHideCloseButton": true // true: hide the close button in the upper right corner; false: show the close button; default is false. }
2.32 Is it possible to replace the text "Mini Program" in the SDK with another name?
Answer: Yes.
You can achieve this through SDK initialization configuration parameters, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setAppletText("X Application") // Replace "Mini Program" text in the SDK with "X Application"
.build();
2.33 Will the data being reported be compressed?
Answer: By default, the SDK does not compress the data being reported. If you want to enable compression, you can achieve this by configuring the SDK initialization parameters, as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setEnableApmDataCompression(true) // Enable data compression during reporting
.build();
2.34 Is it possible to disable the Mini Program API that retrieves supervisory information?
Answer: Yes.
By default, the SDK allows Mini Programs to call the API that retrieves supervisory information (getSuperviseInfo). To disable this, you can configure the SDK initialization parameters as follows:
java
FinAppConfig finAppConfig = new FinAppConfig.Builder()
.setDisableGetSuperviseInfo(true) // Set whether to prevent Mini Programs from calling the API to obtain supervisory information
.build();
After disabling, when the Mini Program calls getSuperviseInfo
, it will receive a getSuperviseInfo:fail disabled
callback.
2.35 Is it possible to open a trial version of the Mini Program?
Answer: Yes.
The platform supports configuring trial versions and trial members for the Mini Program, and members with trial permissions can open the trial version.
Steps to use the trial version of the Mini Program:
Upload the Mini Program on the platform and configure its trial version. For configuration instructions, please search with Enterprise Operation Guide - 4.4 Debugging.
Pass the user ID when initializing the SDK:
kotlinval config = FinAppConfig.Builder() .setUserId("UserID") // User ID must be in the member list configured for the Mini Program .build()
Open the Mini Program using the SDK-provided interface, as follows:
kotlin/** * Start the Mini Program * * @param context Context * @param startAppletDecryptRequest Request body */ fun startApplet(context: Context, startAppletDecryptRequest: StartAppletDecryptRequest)
The structure of
StartAppletDecryptRequest
is as follows:kotlin/** * Request entity class to start the Mini Program * * @param info Mini Program encrypted information */ data class StartAppletDecryptRequest(val info: String)
The
info
field ofStartAppletDecryptRequest
represents the encrypted information of the Mini Program, corresponding to theinfo
field in the Mini Program trial QR code.For example, if the trial Mini Program QR code content is:
bashhttps://finchat-mop.finogeeks.club/mop/scattered-page/#/sdktip?type=scanOpen&info=SFODj9IW1ENO8OA0El8P79aMuxB1DJvfKenZd7hrnemVCNcJ+Uj9PzkRkf/Pu5nMz0cGjj0Ne4fcchBRCmJO+As0XFqMrOclsqrXaogsaUPq2jJKCCao03vI8rkHilrWxSDdzopz1ifJCgFC9d6v29m9jU29wTxlHsQUtKsk/wz0BROa+aDGWh0rKvUEPgo8mB+40/zZFNsRZ0PjsQsi7GdLg8p4igKyRYtRgOxUq37wgDU4Ymn/yeXvOv7KrzUT&codeType=trial
The value of the
info
field should be:bashSFODj9IW1ENO8OA0El8P79aMuxB1DJvfKenZd7hrnemVCNcJ+Uj9PzkRkf/Pu5nMz0cGjj0Ne4fcchBRCmJO+As0XFqMrOclsqrXaogsaUPq2jJKCCao03vI8rkHilrWxSDdzopz1ifJCgFC9d6v29m9jU29wTxlHsQUtKsk/wz0BROa+aDGWh0rKvUEPgo8mB+40/zZFNsRZ0PjsQsi7GdLg8p4igKyRYtRgOxUq37wgDU4Ymn/yeXvOv7KrzUT
2.36 How to implement third-party login in the Mini Program?
2.36.1 Integrate the FinClip Mini Program SDK
Developers first need to integrate the FinClip Mini Program SDK. For integration guidelines, please search with Android Integration Documentation, which contains detailed integration instructions.
2.36.2 Customize Mini Program Interfaces to Implement Authorized Login
To allow the Mini Program to access data from an APP outside itself, you need to register custom interfaces for the Mini Program. For details on custom interfaces, search with Custom Mini Program Interfaces.
Note
The parameters in this example are determined by the developer in actual development; this example is for demonstration purposes only.
- Custom authorization login API
Since this example requires displaying an authorization dialog during login, we need to obtain the Activity instance; hence, we register this API in the Mini Program process to conveniently access the Activity instance displaying the Mini Program.
java
public class LoginApi extends AbsApi {
// Code definition omitted
private void showAuthDialog(ICallback iCallback) {
new AlertDialog.Builder(activity)
.setTitle("Authorization Login")
.setMessage("Do you authorize this Mini Program to obtain user information?")
.setCancelable(false)
.setPositiveButton("OK", (dialog, which) -> authLoginOnMainProcess(iCallback))
.setNegativeButton("Cancel", (dialog, which) -> iCallback.onFail())
.show();
}
/**
* Since user information is generally stored only in the main process, you cannot obtain data directly in the Mini Program process.
* Therefore, you need to use the callInMainProcess method for cross-process calls. After obtaining the information in the main process, return it to the Mini Program process.
*/
private void authLoginOnMainProcess(ICallback iCallback) {
// Cross-process calling code omitted
}
}
For details on cross-process calling APIs, you can search with Mini Program Process Calls Main Process
Register Custom API in the Mini Program Process
java
if (FinAppClient.INSTANCE.isFinAppProcess(this)) {
// Mini Program Process
initFinClipOnAppletProcess();
} else {
// Main process initialization code omitted
}
java
/**
* Register the Mini Program in the Mini Program process
*/
private void initFinClipOnAppletProcess() {
FinAppProcessClient.INSTANCE.setCallback(new FinAppProcessClient.Callback() {
@Override
public List<IApi> getRegisterExtensionApis(@NotNull Activity activity) {
List<IApi> extensionApis = new ArrayList<>();
extensionApis.add(new LoginApi(activity));
return extensionApis;
}
@Override
public List<IApi> getRegisterExtensionWebApis(@NotNull Activity activity) {
return null;
}
});
}
At this point, the entire process for the Mini Program to obtain the user token from the APP through the custom API is complete.
Note
If the product requirements do not need to display the user authorization prompt dialog, it is recommended to register the custom API in the main process to skip the aforementioned cross-process calling process.
2.36.3 Customize Mini Program Interface to Obtain User Information
The parameters in this example are determined by the developer in actual development; this example is for demonstration purposes only.
Custom Get User Profile API
java
public class ProfileApi extends AbsApi {
// Code definition omitted
/**
* In this example, ProfileApi is registered directly in the main process's extension API,
* so this API is executed in the main process and can directly obtain data.
*/
private void getUserProfile(JSONObject jsonObject, ICallback iCallback) {
// User information retrieval process omitted
}
}
Register API in the Main Process
java
FinCallback<Object> initCallback = new FinCallback<Object>() {
@Override
public void onSuccess(Object result) {
// Register extension API, the API registered here will be executed in the main process.
FinAppClient.INSTANCE
.getExtensionApiManager()
.registerApi(new ProfileApi());
}
@Override
public void onError(int code, String error) {
}
@Override
public void onProgress(int status, String error) {
}
};
FinAppClient.INSTANCE.init(this, finAppConfig, initCallback);
At this point, the entire process for the Mini Program to obtain user information from the APP through the custom API is complete.
2.36.4 Customize Mini Program Interface to Check if User Token is Invalid
The parameters in this example are determined by the developer in actual development; this example is for demonstration purposes only.
Custom Check Session API
java
public class AppletSessionApi extends AbsApi {
// Code definition omitted
private void checkSession(JSONObject jsonObject, ICallback iCallback) {
// Checking process code omitted
}
}
Register API in the Main Process
java
FinCallback<Object> initCallback = new FinCallback<Object>() {
@Override
public void onSuccess(Object result) {
// Register extension APIs, the APIs registered here will be executed in the main process.
FinAppClient.INSTANCE
.getExtensionApiManager()
.registerApi(new ProfileApi());
FinAppClient.INSTANCE
.getExtensionApiManager()
.registerApi(new AppletSessionApi());
}
@Override
public void onError(int code, String error) {
}
@Override
public void onProgress(int status, String error) {
}
};
FinAppClient.INSTANCE.init(this, finAppConfig, initCallback);
At this point, the entire process for the Mini Program to check the user token from the APP through the custom API is complete.
2.37 Does it support WebRTC?
Answer: Yes.
2.37.1 Using WebRTC in H5 loaded by the Mini Program
If using WebRTC directly in the H5 loaded by the Mini Program, please search with Common Issues with WebRTC.
2.37.2 Using WebRTC in the Mini Program
If using WebRTC within the Mini Program, you need to integrate the SDK version 2.35.0-alpha20211023v01
or above. Specific usage instructions are as follows:
2.37.2.1 Supported FinClip Android SDK Versions for WebRTC
- Core SDK: 2.35.0-alpha20211023v01
- Extension SDK: 2.35.0-alpha20211023v01
2.37.3 What libraries does it depend on?
- google-webrtc:1.0.32006
2.37.4 Incremental App Size After SDK Integration
- Original size of google-webrtc library:
armeabi-v7a : 4.4 MB (.so files) + 0.9MB (jar file) = 5.3MB
arm64-v8a: 7.1MB (.so files) + 0.9MB (jar file) = 8MB
- After integrating the SDK, the App size may increase by up to 6.2MB.
2.38 Does the Mini Program support offline modes to improve first-load speed?
Starting from version 2.35.1, the SDK supports specifying the paths for the offline Mini Program package and offline basic library package when opening the Mini Program. In this case, the offline package will be used directly to open the Mini Program, speeding up the loading time. Subsequent Mini Programs can still obtain updates from the backend normally.
To obtain the offline Mini Program package and offline basic library package, see the image below:
Interface Definition
/**
* Start the Mini Program
*
* @param context Context
* @param apiServer Server address of the Mini Program's application market
* @param appId Mini Program ID
* @param startParams Parameters passed when starting the Mini Program
* @param offlineLibraryPath Path of the offline basic library
* @param offlineAppletPath Path of the local Mini Program package
*/
fun startApplet(context: Context, apiServer: String, appId: String, startParams: FinAppInfo.StartParams? = null, offlineLibraryPath: String, offlineAppletPath: String)
Call Example
FinAppClient.appletApiManager.startApplet(this, "https://api.finclip.com",
"617bb42f530fb30001509b27", null,
"$filesDir/framework-2.11.4-alpha20211101v01.zip", "$filesDir/分包跳转测试-1.1.1.zip")
2.39 Does the Mini Program support custom More panels?
Answer: Yes.
You can search with CapsuleHandler, where capsule operation delegate and overriding the onMoreButtonClick()
method to show/hide the custom More panel.
Call the
setCapsuleHandler(capsuleHandler: CapsuleHandler)
method of FinAppProcessClient to pass in the CapsuleHandler instance. Implement the show/hide logic for the custom More panel within theonMoreButtonClick()
method, as follows:javaFinAppProcessClient.INSTANCE.setCapsuleHandler(new CapsuleHandler() { @Override public void onMoreButtonClick(@NotNull Context context, @NotNull String appId, @NotNull MoreButtonClickHandler handler) { // Implement the logic to show/hide the custom More panel. // If you do not need a custom More panel, call handler.changeDefaultMoreMenuVisibility() to show/hide the default More panel. } });
Note
The methods of the CapsuleHandler class are executed in the process where the Mini Program resides.
Use the methods provided by the
MoreMenuHelper
class to implement functionalities of the SDK default menu items. The method definitions are as follows:kotlin/** * Trigger forwarding action, consistent with the "Forward" behavior of the SDK default menu. * You need to handle the forwarding logic in the proxy method shareAppMessage(). */ fun invokeForwardMenuAction(context: Context) /** * Feedback and complaints */ fun goToFeedbackPage(context: Context) /** * Open the About page */ fun goToAboutPage(context: Context, appId: String) /** * Open the settings page */ fun goToSettingPage(context: Context, appId: String, appTitle: String) /** * Open or close Mini Program debugging (vConsole) * * @param enableAppletDebug true to open, false to close */ fun setEnableAppletDebug(context: Context, enableAppletDebug: Boolean) /** * Whether Mini Program debugging (vConsole) is enabled or disabled */ fun isEnableAppletDebug(context: Context): Boolean /** * Get the menu data of type [MoreMenuType.ON_MINI_PROGRAM] * * @param callback Parameter field description refers to the proxy method onRegisteredMoreMenuItemClicked() */ fun getMiniProgramTypeMenuData( context: Context, menuId: String?, callback: (appId: String, path: String, menuItemId: String, appInfo: String?, bitmap: Bitmap?) -> Unit ) /** * Check if the Mini Program implements custom menu functionality. * The onShareAppMessage event is affected by whether the Mini Program has called the showShareMenu/hideShareMenu API. * If the Mini Program calls showShareMenu and then checks this method, the value of this event will be true, regardless of whether the Mini Program has implemented the onShareAppMessage event. * If the Mini Program calls hideShareMenu and then checks this method, the value of this event will be false, regardless of whether the Mini Program has implemented the onShareAppMessage event. * * @param callback result JSONArray elements: {"eventName":"Mini Program event name","menuId":"Icon ID","value":"Is the event implemented?"} */ fun checkMenus( activity: FinAppHomeActivity, pageWebViewId: Int?, menuIds: List<String>, callback: (result: JSONArray) -> Unit )
Note
The MoreMenuHelper class needs to be used in the process where the Mini Program resides.
Example:
java
public class App extends Application {
private final Handler handler = new Handler();
private static final String CUSTOM_MENU_ID = "customMenu";
@Override
public void onCreate() {
super.onCreate();
if (!FinAppClient.INSTANCE.isFinAppProcess(this)) {
initFinClipOnMainProcess(); // Main process
} else {
initFinClipOnAppletProcess(); // Mini Program process
}
}
private void initFinClipOnMainProcess() {
// Initialization configuration...
FinCallback<Object> callback = new FinCallback<Object>() {
@Override
public void onSuccess(Object result) { // SDK initialization successful
setCapsuleHandler(); // If the Mini Program needs to run in single process mode, it needs to be set in the main process.
setAppletHandler();
}
@Override
public void onError(int code, String error) { // SDK initialization failed
Toast.makeText(App.this, "SDK initialization failed", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgress(int status, String error) {
}
};
// Initialize FinClipSDK
FinAppClient.INSTANCE.init(this, config, callback);
}
private void initFinClipOnAppletProcess() {
setCapsuleHandler(); // If the Mini Program needs to run in multiple process mode, it needs to be set in the Mini Program process.
}
/**
* Set the capsule operation delegate
*/
private void setCapsuleHandler() {
FinAppProcessClient.INSTANCE.setCapsuleHandler(new CapsuleHandler() {
/**
* The "More" button of the Mini Program capsule is clicked
*
* @param context Mini Program context
* @param appId Mini Program ID
*/
@Override
public void onMoreButtonClick(@NotNull final Context context, @NotNull final String appId, @NotNull MoreButtonClickHandler handler) {
// Note: This is the process where the Mini Program resides.
// Show custom More panel logic. If you do not need a custom More panel, call handler.changeDefaultMoreMenuVisibility() to show/hide the default More panel.
// For share configuration, refer to: [Development] -> [API] -> [Custom Menu] -> [Share Configuration]
ArrayList<String> menuIds = new ArrayList<>();
menuIds.add("WXShareAPPFriends"); // Menu configuration information is provided in the onShareAppMessage method of the Mini Program.
menuIds.add("WXShareAPPMoments"); // Menu configuration information is provided in the onShareAppMessage method of the Mini Program.
menuIds.add(CUSTOM_MENU_ID); // Menu configuration information is provided in the onCustomMenuButtonHandler method of the Mini Program.
MoreMenuHelper.checkMenus(context, menuIds, new Function1<JSONArray, Unit>() {
@Override
public Unit invoke(JSONArray result) {
// Note: This is the Mini Program process.
boolean forwardMenuEnable = false; // Whether the forward menu is available
boolean customMenuEnable = false; // Whether the custom menu is available
// Iterate to obtain button availability status
for (int i = 0; i < result.length(); i++) {
JSONObject jsonObject = (JSONObject) result.opt(i);
if (jsonObject != null) {
String eventName = jsonObject.optString("eventName");
if (eventName.equals("onShareAppMessage")) { // Icon IDs are WXShareAPPFriends or WXShareAPPMoments
boolean value = jsonObject.optBoolean("value");
if (value) {
forwardMenuEnable = true;
}
}
if (eventName.equals("onCustomMenuButtonHandler")) { // Icon ID is customMenu
boolean value = jsonObject.optBoolean("value");
if (value) {
customMenuEnable = true;
}
}
}
}
showMenuDialog(context, appId, forwardMenuEnable, customMenuEnable);
return null;
}
});
}
});
}
private void showMenuDialog(final Context context, final String appId, boolean forwardMenuEnable, boolean customMenuEnable) {
String enableAppletDebug;
if (MoreMenuHelper.isEnableAppletDebug(context)) {
enableAppletDebug = "Disable Debugging";
} else {
enableAppletDebug = "Enable Debugging";
}
new MenuDialog(context)
// Set menu button states based on method parameters; this is omitted...
.setListener(new BottomSheetListener() {
/**
* Menu button click event
*/
@Override
public void onSheetItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.about) {
// About page
MoreMenuHelper.goToAboutPage(context, appId);
} else if (itemId == R.id.setting) {
// Settings page
String appTitle = "";
FinAppInfo appInfo = FinAppProcessClient.INSTANCE.getAppletProcessApiManager().getAppletInfo();
if (appInfo != null) {
appTitle = appInfo.getAppTitle();
}
MoreMenuHelper.goToSettingPage(context, appId, appTitle);
} else if (itemId == R.id.feedback) {
// Feedback and complaints
MoreMenuHelper.goToFeedbackPage(context);
} else if (itemId == R.id.forward) {
// Trigger forwarding action, consistent with the "Forward" behavior of the SDK default menu.
// You need to handle the forwarding logic in the proxy method shareAppMessage().
// Refer to: [Mini Program SDK] -> [Android] -> [Common Issues] -> [How to set the number of Mini Programs that can be opened simultaneously?]
MoreMenuHelper.invokeForwardMenuAction(context);
} else if (itemId == R.id.customMenu) { // This menu requires Mini Program information
// Obtain the menu data of type [MoreMenuType.ON_MINI_PROGRAM]
// Parameter field descriptions refer to the proxy method onRegisteredMoreMenuItemClicked();
// Refer to: [Mini Program SDK] -> [Android] -> [Common Issues] -> [How to inject my menu items into the 'More' menu?]
MoreMenuHelper.getMiniProgramTypeMenuData(context, CUSTOM_MENU_ID, new Function5<String, String, String, String, Bitmap, Unit>() {
@Override
public Unit invoke(String appId, String path, String menuItemId, String appInfo, Bitmap bitmap) {
// Note: This is the Mini Program process.
// Custom menu business logic...
return null;
}
});
} else {
// Open or close Mini Program debugging (vConsole)
MoreMenuHelper.setEnableAppletDebug(context, !MoreMenuHelper.isEnableAppletDebug(context));
}
}
})
.show();
}
private void setAppletHandler() {
FinAppClient.INSTANCE.getAppletApiManager().setAppletHandler(new IAppletHandler() {
/**
* Forward Mini Program
*
* @param appInfo Mini Program information, a JSON string containing the Mini Program ID, name, icon, user ID, and sharing details.
* @param bitmap Mini Program cover image. If [appInfo].params.imageUrl field is an http or https link, the cover image will be obtained from the [appInfo].params.imageUrl; otherwise, the cover image will be taken from [bitmap].
* @param callback Callback for the result of forwarding the Mini Program.
*
* For reference: [Mini Program SDK] -> [Android] -> [Common Issues] -> [How to share Mini Programs to platforms that support Mini Programs, such as WeChat?]
*/
@Override
public void shareAppMessage(@NotNull String appInfo, @Nullable Bitmap bitmap, @NotNull final IAppletCallback callback) {
handler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(null);
}
});
}
});
}
}
2.40 Can Mini Programs run in single-task mode?
Answer: Yes.
When a Mini Program is launched, the SDK, by default, runs the Mini Program in a multi-task manner. This is most intuitively reflected in the recent tasks list of the system, where the Host App and Mini Program are displayed as separate tasks. The SDK allows the configuration of the Mini Program to run in single-task mode, meaning that in the system's recent tasks list, the Host App and the Mini Program will be displayed in the same task. The setup method is as follows:
When calling the start Mini Program interface, set the isSingleTask
field value of the IFinAppletRequest
object to true
.
IFinAppletRequest
:
kotlin
/**
* Indicates whether to open the Mini Program through a single task stack
*/
internal var isSingleTask: Boolean = false
/**
* Set whether to open the Mini Program through a single task stack
*/
fun setSingleTask(isSingleTask: Boolean): IFinAppletRequest {
this.isSingleTask = isSingleTask
return this
}
Example:
java
FinAppClient.INSTANCE.getAppletApiManager().startApplet(this, IFinAppletRequest.Companion.fromAppId("Mini Program ID").setSingleTask(true), null);
2.41 How to load Mini Programs using J2V8?
The SDK supports using J2V8 to load Mini Programs. To enable J2V8, follow the steps below:
Add the jitpack repository in the outer
build.gradle
file of the Android project:groovyallprojects { repositories { ... other repositories ... maven { url "https://jitpack.io" } ... other repositories ... } }
Add the following dependencies to the
build.gradle
file of the Android App module:groovy// j2v8 implementation 'com.eclipsesource.j2v8:j2v8:6.2.1@aar' // j2v8-debugger // If you want to debug J2V8 through Chrome DevTools, you must depend on j2v8-debugger, otherwise it is optional implementation('com.github.AlexTrotsenko:j2v8-debugger:0.2.3') { exclude group: 'com.eclipsesource.j2v8' exclude group: 'com.android.support' }
If you depend on j2v8-debugger and encounter the following error during the APP build:
Manifest merger failed : uses-sdk:minSdkVersion 19 cannot be smaller than version 23 declared in library [com.github.AlexTrotsenko:j2v8-debugger:0.2.3] xxx/j2v8-debugger-0.2.3/AndroidManifest.xml as the library might be using APIs not available in 19 Suggestion: use a compatible library with a minSdk of at most 19, or increase this project's minSdk version to at least 23, or use tools:overrideLibrary="com.alexii.j2v8debugger" to force usage (may lead to runtime failures)
You need to add the following code in the
AndroidManifest.xml
file of the App module:xml<uses-sdk tools:overrideLibrary="com.alexii.j2v8debugger" />
Add J2V8 obfuscation rules in the App module as follows:
properties# J2V8 -keep class com.eclipsesource.v8.** {*;}
2.42 Does FinClip SDK support setting languages? How to set it?
FinClip Android SDK has supported setting the SDK's language type since version 2.40.0-alpha20230106v02. This language type will affect the text language of public UI elements in the SDK (such as More Panels, About, Settings, Complaint Feedback, etc.). Currently, it only supports Simplified Chinese and English. When setting other languages, the default value will be displayed in Simplified Chinese.
How to set it? In FinAppConfig
, there is a configuration item called locale
. Set this value during initialization.
Example Code:
kotlin
val config = FinAppConfig.Builder()
.setLocale(Locale.SIMPLIFIED_CHINESE)
.build()
2.43 What is the maximum number of Mini Programs that can run simultaneously?
Android Mini Programs use a multi-process approach for execution, with each Mini Program running in a new process. When a Mini Program is closed through the capsule, its process is merely pushed to the background.
A maximum of 5 Mini Programs can run simultaneously, which can be configured via initialization configuration items.
Note
The range of configurable numbers is 1-5. Setting a value <=0 or >5 will not take effect.
kotlin
val config = FinAppConfig.Builder()
.setSdkKey("SDK Key")
.setSdkSecret("SDK Secret")
.setMaxRunningApplet(3) // Set the maximum number of running Mini Programs
.build()
java
FinAppConfig config = new FinAppConfig.Builder()
.setFinStoreConfigs(storeConfigs) // Server information collection
.setMaxRunningApplet(3)
.build();
2.44 How to set the foreground service to keep the app running?
When a Mini Program is opened, the app runs in the background. At this point, the app may be killed by the system. You can configure a foreground service to keep the app running and prevent it from being killed by the system.
kotlin
val config = FinAppConfig.Builder()
.setForegroundServiceConfig(
FinAppConfig.ForegroundServiceConfig(
true, // Whether to start the foreground service
R.drawable.ic_launcher, // Icon of the foreground service
"Mini Program is running", // Title of the foreground service
"",
notificationChannelId, // Notification channel ID
notificationChannelName, // Notification channel name
notificationChannelDesc, // Notification channel description
)
)
.build()
FinAppClient.init(application, config, object : FinCallback<Any?> {})
java
FinAppConfig.ForegroundServiceConfig foregroundServiceConfig = new FinAppConfig.ForegroundServiceConfig(true, R.drawable.ic_launcher, "Mini Program is running", "", notificationChannelId, notificationChannelName, notificationChannelDesc);
FinAppConfig config = new FinAppConfig.Builder()
.setForegroundServiceConfig(foregroundServiceConfig)
.setFinStoreConfigs(storeConfigs) // Server information collection
.setUiConfig(uiConfig)
.setMaxRunningApplet(3)
.build();
2.45 How to set Mini Program processes to close when the main process is closed?
By default, when the main app process is closed, the Mini Program can still run independently. You can configure it so that the Mini Program process also closes when the app process is closed or killed.
kotlin
val config = FinAppConfig.Builder()
.setBindAppletWithMainProcess(true) // Close the Mini Program process when the main process is closed
.setKillAppletProcessNotice("The APP has been closed, the Mini Program cannot be used independently. Please reopen the APP to use the Mini Program.")
.build()
FinAppClient.init(application, config, object : FinCallback<Any?> {})
java
FinAppConfig config = new FinAppConfig.Builder()
.setFinStoreConfigs(storeConfigs) // Server information collection
.setBindAppletWithMainProcess(true)
.setKillAppletProcessNotice("The APP has been closed, the Mini Program cannot be used independently. Please reopen the APP to use the Mini Program.")
.build();
2.46 How to internationalize the SDK?
Answer: The SDK has supported internationalization and currently supports both Chinese and English languages. If you need the SDK to support other languages, you can implement it through the following steps:
- First, confirm which SDKs you have introduced. Take the core SDK [finapplet] as an example:
groovy
implementation 'com.finogeeks.lib:finapplet:2.42.4-dev20231107v07'
Find the core SDK [finapplet] aar file in your project, as well as all English resource files.
Copy the texts from the English resource file [values-en] to the corresponding folder in your project requiring internationalization; then maintain the keys and translate the English into the required language.
Place the translated texts into the corresponding language directory (directory names are specified by Android and can refer to https://juejin.cn/post/7115376916281950244.
Attention:
The translation of "Mini Program" may be customized according to your decision (some clients may customize it to something else, such as Quick Application, etc.);
Placeholder texts in the translation must be preserved; removing them may cause crashes;
In cases where some keys differ, but the texts are the same, these should not be omitted;
Not all SDKs will have English resource files; if there are no English resource files [values-en], then there is no need for internationalization;
If compilation errors occur after adding internationalization resources, try adding the following configuration in the app/build.gradle file:
groovyandroid { // Other existing configurations lintOptions { checkReleaseBuilds false abortOnError false } }
2.47 How to customize the data source for the Picker's province, city, and district?
Answer: Starting from version 2.43.1
, the Host App supports customizing the data source for the Picker’s province, city, and district.
When initializing the SDK, pass the desired data source. Example code:
kotlin
val config = FinAppConfig.Builder()
.setPickerRegionPath(file)
.build()
FinAppClient.init(application, config, callback)
Where file
is the custom data source file object, supporting json format data. Reference: example.json
3. Debugging
3.1 What tool can be used to debug Mini Programs during development?
Answer: The Android Mini Programs SDK uses Tencent's TBS browsing service (X5 kernel), and the debugging tool is TBS Studio. TBS Studio can debug Mini Programs similarly to debugging web pages in Chrome browser.
Note
Since version 2.33.3
, the SDK has replaced the X5 kernel with system webview.
3.2 Why can't TBS Studio start debugging, always prompting that the current target App cannot perform TBS debugging? Please ensure the following checks and operations: Ensure that the current target App's Webview is based on TBS development; Ensure that the preceding steps were successful.
Answer: This situation typically occurs because the current device is a 64-bit processor device and the application is not set to run in 32-bit mode. TBS SDK versions prior to 43903 do not provide 64-bit so dynamic libraries. If the app runs in 64-bit mode on 64-bit processor devices, the TBS SDK initialization will fail, and the X5 kernel will not be successfully enabled.
To enable the X5 kernel on 64-bit processor devices, set the application to run in 32-bit mode in the build.gradle
file of the current Android project under defaultConfig
as follows:
bash
ndk {
// Set the supported SO library architecture
abiFilters "armeabi", 'armeabi-v7a'
}
If compilation errors occur after configuration, you can resolve this by adding the following configuration in the project's gradle.properties
file:
bash
Android.useDeprecatedNdk=true;
3.3 Why does the Mini Program continue to show a blank screen when loading web pages on some lower version systems, while it does not happen on higher version systems?
Answer: This situation generally arises because the browser version in lower version systems is also quite low, causing it to fail to recognize new syntactical features. For example, some browser versions were released before the finalization of ES6, and if ES6 features are used during development, an older browser version won't recognize the ES6 code when the web page is opened, resulting in errors.
For such issues, it is generally recommended to:
- Use compatibility-friendly syntax as much as possible while coding;
- If unavoidable new syntax features need to be used, consider introducing syntax transformation tools, such as babel-polyfill, to automatically convert new syntax to lower-version syntax. This way, you won't have to worry about environment compatibility while using new syntax features.
3.4 How to enable vConsole for debugging Mini Programs?
If you need to use vConsole to debug Mini Programs, there are currently various ways to enable Debug mode.
- Setting
setAppletDebugMode
in the SDK initialization configuration toFinAppConfig.AppletDebugMode.appletDebugModeEnable
will allow all Mini Programs to display vconsole. Please keep this configuration set toappletDebugModeDisable
when the application goes live (when set toappletDebugModeEnable
, vConsole cannot be closed via API within the Mini Program). - When
setEnableAppletDebug
in the SDK initialization configuration is set toappletDebugModeDisable
, each Mini Program can independently enable Debug mode. In cases where the option to hide the debug button in more menus has not been set, non-online versions (such as experience version, audit version, development version, preview version) can enable Debug mode through the 【Open Debug】 option in the more menu. - When
setEnableAppletDebug
is set toappletDebugModeDisable
, Mini Programs can call the API (ft.setEnableDebug
) to enable Debug mode.
For debugging Mini Programs, there are currently several ways to open vconsole, allowing you to see logs within the Mini Program.
SDK Side There are two areas within the SDK that influence the opening and closing of vconsole:
- The
appletDebugMode
parameter in the initialization configuration itemFinAppConfig
; - The 【Open Debug】 and 【Close Debug】 buttons in the more panel.
The appletDebugMode
is an enumerated type with five values:
appletDebugModeUndefined
: Default value; vconsole is not displayed, and Mini Programs can callsetEnableDebug
.appletDebugModeEnable
: Forces all Mini Programs (all versions) to enable vconsole, and does not allow Mini Programs to callsetEnableDebug
.appletDebugModeDisable
: vconsole is not enabled, and Mini Programs can callsetEnableDebug
.appletDebugModeForbidden
: Forces all Mini Programs (all versions) to disable vconsole, and does not allow Mini Programs to callsetEnableDebug
.appletDebugModeForbiddenRelease
: All official Mini Programs disable vConsole and do not allow official versions to callsetEnableDebug
; other versions have the same effect as Undefined.
Mini Program Side The Mini Program can call the Mini Program API (ft.setEnableDebug
) to enable vconsole.
However, if appletDebugMode
is set to appletDebugModeEnable
, the ft.setEnableDebug
interface will not be effective. Similarly, if appletDebugMode
is set to appletDebugModeForbidden
, the ft.setEnableDebug
interface will also not be effective.
Finally, it is recommended to set appletDebugMode
to appletDebugModeEnable
during the app development phase; then change it to appletDebugModeDisable
when submitting the app for review. Setting it to appletDebugModeDisable
and not configuring to hide additional menu debugging buttons, the official Mini Programs will not display the 【Open Debug】 and 【Close Debug】 buttons. However, they can still call the API (ft.setEnableDebug
) to enable vconsole. Non-official Mini Programs can use 【Open Debug】 and ft.setEnableDebug
to enable vconsole.