MiniApp SDK
Learn how to register and use custom functions from the Nana host app within your mini applications using the MiniApp SDK.
MiniApp SDK - Custom Function Registration
Introduction
The MiniApp SDK provides a powerful mechanism for registering and using custom functions from the Nana host app within your mini applications. This feature allows your mini app to access host app functionalities through a standardized API interface, enabling seamless integration between your mini app and the Nana platform.
Custom function registration creates a bridge between your mini app and the host application, allowing you to:
- Access host app services and data
- Leverage existing host app functionalities
- Maintain consistent user experiences across the platform
- Implement custom business logic specific to your mini app needs
Setting Up Custom Functions
Step 1: Access the Host App Configuration
- Navigate to apps.nana.sa
- Go to your Host App section
- Navigate to APIs and Menus
- Select Configure Custom API
In this section, you'll see all available registered functions from the host app. These functions are categorized as:
- Public functions: Available to all mini apps
- Private functions: Restricted access based on permissions
Step 2: Create the Configuration File
In your mini app's root directory, create a new file called NanaConf.js. This file will contain the configuration for all the registered functions you want to use in your mini app.
module.exports = {
extApi: [
{
name: 'getUserMobile',
sync: false,
params: {}
},
{
name: 'getUserName',
sync: false,
params: {}
},
// Add more registered functions as needed
]
}Once configured, you can use the registered functions in your code:
const userID = ft.getUserName({
success: (res) => {
console.log('User name retrieved successfully:', res);
// Handle successful response
},
fail: (res) => {
console.log('Failed to get user name:', res);
// Handle error response
}
});Function Parameters Explanation
User Information Functions
getUserId
Retrieves the current user's ID.
NanaConf.js Configuration:
{
name: 'getUserId',
sync: false,
params: {},
}Usage Example:
const userID = ft.getUserId({
success: (res) => {
console.log('User ID:', res);
// res contains: {'userId': 'userid'}
},
fail: (res) => {
console.log('Error getting user ID:', res);
}
});Response Format:
{'userId': 'userid'}getUserMobile
Gets the user's mobile number.
NanaConf.js Configuration:
{
name: 'getUserMobile',
sync: false,
params: {}
}Usage Example:
const userMobile = ft.getUserMobile({
success: (res) => {
console.log('User Mobile:', res);
// res contains: {'userMobile': '0555555555'}
},
fail: (res) => {
console.log('Error getting user mobile:', res);
}
});Response Format:
{'userMobile': '0555555555'}getUserName
Fetches the user's name.
NanaConf.js Configuration:
{
name: 'getUserName',
sync: false,
params: {}
}Usage Example:
const userName = ft.getUserName({
success: (res) => {
console.log('User Name:', res);
// res contains: {'userName': 'nawaf dallah'}
},
fail: (res) => {
console.log('Error getting user name:', res);
}
});Response Format:
{'userName': 'nawaf dallah'}getAppLang
Returns the current app language.
NanaConf.js Configuration:
{
name: 'getAppLang',
sync: false,
params: {}
}Usage Example:
const appLang = ft.getAppLang({
success: (res) => {
console.log('App Language:', res);
// res contains: {'language': 'ar'}
},
fail: (res) => {
console.log('Error getting app language:', res);
}
});Response Format:
{'language': 'ar'}userLoggedIn
Checks if user is logged in.
NanaConf.js Configuration:
{
name: 'userLoggedIn',
sync: false,
params: {}
}Usage Example:
const loginStatus = ft.userLoggedIn({
success: (res) => {
console.log('User logged in status:', res);
// res contains: {'isLoggedIn': true}
if (res.isLoggedIn) {
// User is logged in
} else {
// User is not logged in
}
},
fail: (res) => {
console.log('Error checking login status:', res);
}
});Response Format:
{'isLoggedIn': true}getUserToken
Retrieves the user's authentication token.
NanaConf.js Configuration:
{
name: 'getUserToken',
sync: false,
params: {}
}Usage Example:
const userToken = ft.getUserToken({
success: (res) => {
console.log('User Token:', res);
// res contains: {'token': 'hjgds8726382ddshc87@879...'}
// Use this token for authenticated API calls
},
fail: (res) => {
console.log('Error getting user token:', res);
}
});Response Format:
{'token': 'hjgds8726382ddshc87@879...'}getUserAddress
Gets the user's address information.
NanaConf.js Configuration:
{
name: 'getUserAddress',
sync: false,
params: {}
}Usage Example:
const userAddress = ft.getUserAddress({
success: (res) => {
console.log('User Address:', res);
// res contains complete address object
},
fail: (res) => {
console.log('Error getting user address:', res);
}
});Response Format:
{
'address': {
"address_id": "cb175f5e29",
"manual_location": null,
"type_second_info": "",
"state": "الرياض",
"city": "الرياض",
"title": "Office",
"is_supported": 1,
"latitude": "24.764998609744307",
"type_first_info": "",
"type": null,
"zip_code": null,
"kind": "first",
"country": "Saudi Arabia",
"longitude": "46.71348897092447",
"manually_update_title": null,
"isManual": null,
"food_city_id": 1
}
}Commerce Functions
addToCart
Adds an item to the shopping cart.
NanaConf.js Configuration:
{
name: 'addToCart',
sync: false,
params: {
retailer_id: '',
pid: '',
quantity: 0,
image: '',
price: 0.0,
promotionId: '',
name: '',
addedFrom: '',
resolvedBidId: '',
pricingStyle: '',
}
}Usage Example:
const addItemResult = ft.addToCart({
retailer_id: 'retailer_123', // (string) The retailer identifier
pid: 'product_456', // (string) Product identifier
quantity: 2, // (number) Quantity of items to add
image: 'https://example.com/product-image.jpg', // (string) Product image URL
price: 29.99, // (number) Product price
promotionId: 'promo_789', // (string) Promotion identifier if applicable
name: 'Sample Product', // (string) Product name
addedFrom: 'miniapp', // (string) Source where item was added from
resolvedBidId: 'bid_101', // (string) Resolved bid identifier
pricingStyle: 'standard', // (string) Pricing style information
success: (res) => {
console.log('Item added to cart successfully:', res);
// res contains: {'success': true, 'message': 'Product added to cart!'}
},
fail: (res) => {
console.log('Failed to add item to cart:', res);
// Handle error response
}
});Response Format:
{'success': true, 'message': 'Product added to cart!'}orderPayment
Processes order payment by showing a payment bottom sheet with available payment methods (Apple Pay, Mada, etc.). Important: You must first create a payment session using the API before calling this function.
NanaConf.js Configuration:
{
name: 'orderPayment',
sync: false,
params: {
data: {},
}
}Step 1: Get User Token
First, you need to get the user's authentication token:
ft.getUserToken({
success: (userTokenRes) => {
console.log('User Token:', userTokenRes.token);
// Use this token to create payment session
createPaymentSession(userTokenRes.token);
},
fail: (res) => {
console.log('Error getting user token:', res);
}
});Step 2: Create Payment Session
Create a payment session using the API:
async function createPaymentSession(userToken) {
const miniAppApiKey = 'your_miniapp_api_key'; // Your mini app API key
try {
const response = await new Promise((resolve, reject) => {
wx.request({
url: 'https://miniapps.nana.sa/api/v2/mobile-user-activities/create-payment-session',
method: 'POST',
header: {
'Content-Type': 'application/json',
'miniapp-api-key': miniAppApiKey,
'miniapp-user-token': `Bearer ${userToken}`
},
data: {
amount: 10, // (number) Payment amount
reference: 'order_ref_12345' // (string) Unique payment reference
},
success: (res) => {
resolve(res.data);
},
fail: (err) => {
reject(new Error(`Network Error: ${err.errMsg}`));
}
});
});
if (response.success) {
// Get the mini app ID
const appInfo = wx.getAccountInfoSync();
const appId = appInfo.miniProgram.appId;
// Add mini app ID to the response data
response.data.mini_app_id = appId;
// Now call orderPayment with the session data
processPayment(response.data);
} else {
console.error('Failed to create payment session:', response);
}
} catch (error) {
console.error('Error creating payment session:', error);
}
}Step 3: Process Payment
Use the payment session data with orderPayment:
function processPayment(paymentSessionData) {
ft.orderPayment({
data: paymentSessionData, // (object) The complete payment session data from API response
success: (res) => {
console.log('Payment processed successfully:', res);
// Handle successful payment
// The payment bottom sheet will be shown with available methods
},
fail: (res) => {
console.log('Payment failed:', res);
// Handle payment failure
}
});
}Complete Payment Workflow Example:
async function handlePayment() {
try {
// Step 1: Get user token
ft.getUserToken({
success: async (userTokenRes) => {
try {
// Step 2: Create payment session
const miniAppApiKey = 'your_miniapp_api_key';
const sessionResponse = await new Promise((resolve, reject) => {
wx.request({
url: 'https://miniapps.nana.sa/api/v2/mobile-user-activities/create-payment-session',
method: 'POST',
header: {
'Content-Type': 'application/json',
'miniapp-api-key': miniAppApiKey,
'miniapp-user-token': `Bearer ${userTokenRes.token}`
},
data: {
amount: 10,
reference: 'order_ref_12345'
},
success: (res) => resolve(res.data),
fail: (err) => reject(new Error(`Network Error: ${err.errMsg}`))
});
});
if (sessionResponse.success) {
// Add mini app ID
const appInfo = wx.getAccountInfoSync();
sessionResponse.data.mini_app_id = appInfo.miniProgram.appId;
// Step 3: Call orderPayment
ft.orderPayment({
data: sessionResponse.data,
success: (res) => {
console.log('Payment initiated successfully:', res);
},
fail: (res) => {
console.error('Payment failed:', res);
}
});
}
} catch (error) {
console.error('Error in payment process:', error);
}
},
fail: (res) => {
console.log('Error getting user token:', res);
}
});
} catch (error) {
console.error('Payment process failed:', error);
}
}Expected Payment Session Response Structure:
{
"status_code": 200,
"result": "Operation Completed Successfully",
"success": true,
"data": {
"payment_session_secret": "pss_4db7628a-c555-4f86-93f6-0be2a384abd6",
"payment_session_token": "YmFzZTY0:eyJpZCI6InBzXzM0SDNPMm81VFZpNHhiblo0QVU1dFFURllrcSIs...",
"id": "ps_34H3O2o5TVi4xbnZ4AU5tQTFYkq",
"_links": {
"self": {
"href": "https://api.sandbox.checkout.com/payment-sessions/ps_34H3O2o5TVi4xbnZ4AU5tQTFYkq"
}
}
// Additional payment configuration data...
}
}What happens after calling orderPayment:
- A payment bottom sheet will appear in the mini app
- Users can select from available payment methods (Apple Pay, Mada, Credit Card, etc.)
- The payment will be processed through the selected method
- Success/failure/cancel callbacks will be triggered based on the payment result
For more details about the create payment session API, visit: Payment API Documentation
Navigation Functions
closeMiniApp
Closes the current mini app.
NanaConf.js Configuration:
{
name: 'closeMiniApp',
sync: false,
params: {
miniAppId: ''
}
}Usage Example:
ft.closeMiniApp({
miniAppId: 'your_miniapp_id', // (string) The identifier of the mini app to close
success: (res) => {
console.log('Mini app closed successfully');
},
fail: (res) => {
console.log('Failed to close mini app:', res);
}
});closeMiniAppAndOpenDeepLink
Closes mini app and opens a deep link.
NanaConf.js Configuration:
{
name: 'closeMiniAppAndOpenDeepLink',
sync: false,
params: {
miniAppId: '',
deepLink: '',
}
}Usage Example:
ft.closeMiniAppAndOpenDeepLink({
miniAppId: 'your_miniapp_id', // (string) The identifier of the mini app to close
deepLink: 'https://nana.sa/profile', // (string) The deep link URL to open
success: (res) => {
console.log('Mini app closed and deep link opened successfully');
},
fail: (res) => {
console.log('Failed to close mini app and open deep link:', res);
}
});Configuration Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Custom API name |
| sync | boolean | no | Is it a synchronous API? |
| overwrite | boolean | no | Whether to overwrite the API with the same name |
| pluginId | array or string | no | This parameter is valid only when calling loadExtApi in the applet, indicating that the plug-ins in the id list are allowed to use the custom API. |
| scope | string | no | Supported by the basic library 3.5.6 and later. This parameter is valid only when calling loadExtApi in the plugin. The optional values are default, self, all. The default value is default |
| params | object | no | The parameter format can only list the required attributes. If there are no restrictions, you can directly use an empty object. |
Best Practices
Function Naming
- Use clear, descriptive function names that indicate their purpose
- Follow camelCase convention for consistency
- Avoid special characters or spaces in function names
Error Handling
- Always implement both
successandfailcallbacks - Provide meaningful error messages to help with debugging
- Consider implementing retry logic for critical functions
Parameter Validation
- Validate required parameters before calling registered functions
- Use TypeScript for better parameter type checking
- Document expected parameter formats and constraints
Performance Considerations
- Use synchronous functions sparingly as they can block the UI
- Implement loading states for asynchronous operations
- Cache results when appropriate to reduce redundant API calls
Troubleshooting
Function Not Found
- Verify the function name matches exactly with the host app registration
- Check if the function is marked as public and accessible to your mini app
- Ensure the
NanaConf.jsfile is in the correct location
Parameter Errors
- Validate that all required parameters are provided
- Check parameter types match the expected format
- Review parameter names for typos or case sensitivity issues
Callback Issues
- Ensure both
successandfailcallbacks are properly defined - Check for syntax errors in callback functions
- Verify callback parameters are handled correctly
This documentation provides a comprehensive guide for implementing custom function registration in your mini app, enabling powerful integration with the Nana host application.
Updated 10 days ago
