Objective-C Signing SDK Integration Guide
Overview
The Objective-C signing SDK generates the X-Sdk-Date and Authorization headers required by Meitu Open Platform APIs and returns an NSURLRequest that can be sent directly with NSURLSession. It uses the SDK-HMAC-SHA256 algorithm to sign requests with an AK/SK pair.
Store the SK on the server and never embed it in a published iOS, macOS, or other client application.
Requirements
- Apple Objective-C project
- Foundation
- CommonCrypto
- NSURLSession
- ARC
The SDK does not declare a minimum OS version. Use the deployment target and compiler settings required by your application.
Download and integration
SDK version: 1.0.0
Download the Objective-C SDK and example
The archive contains:
AIGCP-API-ObjectiveC-sdk-1.0.0/
├── MTSigner.h
├── MTSigner.m
└── MTDemo.mAdd MTSigner.h and MTSigner.m to the application target, then import the header:
#import "MTSigner.h"API reference
Initialize the signer
- (instancetype)initWithKey:(NSString *)key
secret:(NSString *)secret;| Parameter | Description |
|---|---|
key | Access Key (AK) |
secret | Secret Key (SK) |
Create a signed request
- (NSURLRequest *)signRequest:(NSURL *)url
method:(NSString *)method
headers:(NSDictionary<NSString *, NSString *> *)headers
body:(NSString *)body
error:(NSError **)error;| Parameter | Description |
|---|---|
url | Final request URL, including encoded and sorted query parameters |
method | HTTP method, such as GET or POST |
headers | Headers to sign; must include Host |
body | UTF-8 request body that will be sent; pass @"" for GET |
error | Error output parameter |
The return value is an NSURLRequest containing the request method, headers, and body. Send this object directly; do not rebuild or modify the request after signing.
Header constants
| Constant | Header/value |
|---|---|
kHeaderHost | Host |
kHeaderXDate | X-Sdk-Date |
kHeaderAuthorization | Authorization |
kHeaderContentSha256 | X-Sdk-Content-Sha256 |
kAlgorithm | SDK-HMAC-SHA256 |
If X-Sdk-Date is not supplied, the SDK generates a UTC timestamp. The SDK adds Authorization after signing.
Complete POST example
The following example calls the production synchronous task endpoint at https://openapi.meitu.com/api/v1/sdk/sync/push. The request body contains five top-level fields: task, task_type, init_images, params passed as a JSON string, and sync_timeout. Replace the task, business parameters, image, and timeout values according to the target capability's API documentation.
#import <Foundation/Foundation.h>
#import "MTSigner.h"
static void SendSignedPOST(void) {
NSDictionary *environment = [NSProcessInfo processInfo].environment;
NSString *accessKey = environment[@"MEITU_OPENAPI_AK"];
NSString *secretKey = environment[@"MEITU_OPENAPI_SK"];
if (accessKey.length == 0 || secretKey.length == 0) {
NSLog(@"Missing MEITU_OPENAPI_AK or MEITU_OPENAPI_SK");
return;
}
NSURL *url = [NSURL URLWithString:
@"https://openapi.meitu.com/api/v1/sdk/sync/push"];
NSDictionary *payload = @{
@"task": @"/v1/replace-with-product-task",
@"task_type": @"formula",
@"init_images": @[
@{
@"url": @"https://example.com/input.jpg",
@"profile": @{
@"media_profiles": @{ @"media_data_type": @"url" },
@"version": @"v1"
}
}
],
@"params": @"{\"parameter\":{\"rsp_media_type\":\"url\"}}",
@"sync_timeout": @30
};
NSError *jsonError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:payload
options:0
error:&jsonError];
if (jsonData == nil) {
NSLog(@"Failed to serialize request JSON: %@", jsonError);
return;
}
NSString *body = [[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSDictionary<NSString *, NSString *> *headers = @{
kHeaderHost: @"openapi.meitu.com",
@"Content-Type": @"application/json; charset=UTF-8",
@"Accept": @"application/json"
};
MTSigner *signer = [[MTSigner alloc] initWithKey:accessKey secret:secretKey];
NSError *signError = nil;
NSURLRequest *request = [signer signRequest:url
method:@"POST"
headers:headers
body:body
error:&signError];
if (request == nil || signError != nil) {
NSLog(@"Failed to sign request: %@", signError);
return;
}
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error != nil) {
NSLog(@"Request failed: %@", error);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSString *responseBody = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTTP %ld", (long)httpResponse.statusCode);
NSLog(@"%@", responseBody);
}];
[task resume];
}Set the environment variables before running the example, then replace task, params, the image information, and sync_timeout with values required by the target API. body is serialized once. The SDK signs the same string's UTF-8 bytes and uses them to create HTTPBody, after which the returned NSURLRequest is sent directly.
GET example
GET requests normally have no body. Percent-encode and sort all query parameters before signing, then place them in the final URL.
NSURL *url = [NSURL URLWithString:
@"https://openapi.meitu.com/api/v1/sdk/status?task_id=replace-with-task-id"];
NSDictionary<NSString *, NSString *> *headers = @{
kHeaderHost: @"openapi.meitu.com",
@"Accept": @"application/json"
};
MTSigner *signer = [[MTSigner alloc] initWithKey:accessKey secret:secretKey];
NSError *signError = nil;
NSURLRequest *request = [signer signRequest:url
method:@"GET"
headers:headers
body:@""
error:&signError];
if (request != nil && signError == nil) {
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error != nil) {
NSLog(@"Request failed: %@", error);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSString *body = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTTP %ld", (long)httpResponse.statusCode);
NSLog(@"%@", body);
}];
[task resume];
}Notes
- Use HTTPS and ensure that
Hostmatches the URL host. Useopenapi.meitu.comfor this domain. methodmust match the request and use uppercase form, such asGETorPOST.- Finalize the URL, query, signed headers, and body before signing. Do not modify them afterward.
- Apply RFC 3986 percent encoding and protocol-defined sorting to query parameters before signing. The SDK does not sort the query string.
- POST signing and sending must use identical UTF-8 body bytes. Send the
NSURLRequestreturned by the SDK directly. - Pass
@""as the GET body. - Keep the server clock accurate. The generated
X-Sdk-Dateuses UTC. - By default, the body's SHA-256 digest is signed. If the target API supports excluding the body digest, set this before signing:
headers[kHeaderContentSha256] = @"UNSIGNED-PAYLOAD";Common errors
| Symptom | Resolution |
|---|---|
401, 403, or invalid signature | Check the AK/SK, server time, Host, HTTP method, and whether the URL, headers, or body changed after signing |
| POST signature verification fails | Serialize JSON once and send the request returned by the signer directly; verify Content-Type and the actual UTF-8 body |
| GET signature verification fails | Encode and sort query parameters before signing, and pass @"" as the body |
UNSIGNED-PAYLOAD has no effect | Use kHeaderContentSha256, verify the exact value, and confirm that the target API supports it |
| Request times out or cannot connect | Check HTTPS, DNS, network proxy settings, and NSURLSession timeouts; inspect the completion-handler network error |
| API reports invalid business parameters | Check task, task_type, init_images, params, and sync_timeout against the target capability's API documentation |