2 Commits

Author SHA1 Message Date
305326aa9a 添加placehold颜色 2026-02-03 20:51:48 +08:00
61095a379f 处理网络 2026-02-03 20:22:28 +08:00
5 changed files with 64 additions and 21 deletions

View File

@@ -20,6 +20,10 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret;
/// 获取签名原始拼接字符串HMAC 前的明文)
+ (NSString *)signSourceStringWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret;
/// 秒级时间戳(字符串)
+ (NSString *)currentTimestamp;
@@ -29,4 +33,3 @@ NS_ASSUME_NONNULL_BEGIN
@end
NS_ASSUME_NONNULL_END

View File

@@ -12,10 +12,16 @@
+ (NSString *)urlEncode:(NSString *)value {
if (!value) return @"";
// Swift .urlQueryAllowed
NSCharacterSet *allowed = [NSCharacterSet URLQueryAllowedCharacterSet];
// application/x-www-form-urlencoded
NSMutableCharacterSet *allowed = [NSMutableCharacterSet alphanumericCharacterSet];
[allowed addCharactersInString:@"-._*"];
NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
return encoded ?: value;
if (!encoded) {
return value;
}
// +URLEncoder
encoded = [encoded stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
return encoded;
}
+ (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret {
@@ -41,6 +47,12 @@
+ (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret {
NSString *dataString = [self signSourceStringWithParams:params secret:secret];
return [self hmacSHA256:dataString secret:secret];
}
+ (NSString *)signSourceStringWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret {
// 1. & sign
NSMutableDictionary<NSString *, NSString *> *filtered = [NSMutableDictionary dictionary];
@@ -62,15 +74,11 @@
[components addObject:part];
}
NSString *encodedSecret = [self urlEncode:secret];
NSString *encodedSecret = [self urlEncode:secret ?: @""];
NSString *secretPart = [NSString stringWithFormat:@"secret=%@", encodedSecret];
[components addObject:secretPart];
NSString *dataString = [components componentsJoinedByString:@"&"];
// 4. HMAC-SHA256
NSString *sign = [self hmacSHA256:dataString secret:secret];
return sign;
return [components componentsJoinedByString:@"&"];
}
+ (NSString *)currentTimestamp {
@@ -89,4 +97,3 @@
}
@end

View File

@@ -458,6 +458,8 @@
if (!_searchField) {
_searchField = [[UITextField alloc] init];
_searchField.placeholder = KBLocalized(@"Search Role");
_searchField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:KBLocalized(@"Search Role")
attributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}];
_searchField.textColor = [UIColor whiteColor];
_searchField.font = [UIFont systemFontOfSize:14];
_searchField.clearButtonMode = UITextFieldViewModeWhileEditing;

View File

@@ -119,12 +119,7 @@ autoShowBusinessError:NO
return;
}
NSString *encodedContent =
[content stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *path = [NSString
stringWithFormat:@"%@?content=%@&companionId=%ld", API_AI_CHAT_MESSAGE,
encodedContent ?: @"", (long)companionId];
NSString *path = API_AI_CHAT_MESSAGE;
NSDictionary *params = @{
@"content" : content ?: @"",
@"companionId" : @(companionId)

View File

@@ -33,6 +33,29 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
@implementation KBNetworkManager
static NSString *KBSignStringFromObject(id obj) {
if (!obj || obj == (id)kCFNull) {
return nil;
}
if ([obj isKindOfClass:[NSString class]]) {
return (NSString *)obj;
}
if ([obj isKindOfClass:[NSNumber class]]) {
return [(NSNumber *)obj stringValue];
}
if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDictionary class]]) {
NSJSONWritingOptions options = 0;
if (@available(iOS 11.0, *)) {
options = NSJSONWritingSortedKeys;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:options error:nil];
if (data.length > 0) {
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}
return [obj description];
}
+ (instancetype)shared {
static KBNetworkManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBNetworkManager new]; });
return m;
@@ -73,14 +96,24 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
signParams[@"nonce"] = nonce;
// body
[bodyParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSString class]]) {
signParams[key] = obj;
} else {
signParams[key] = [obj description];
NSString *value = KBSignStringFromObject(obj);
if (value.length == 0) {
return;
}
signParams[key] = value;
}];
NSString *signSource = [KBSignUtils signSourceStringWithParams:signParams secret:secret];
NSString *sign = [KBSignUtils signWithParams:signParams secret:secret];
#if DEBUG
if (signSource.length > 0) {
NSString *secretPart = [NSString stringWithFormat:@"secret=%@", [KBSignUtils urlEncode:secret ?: @""]];
NSString *masked = [signSource stringByReplacingOccurrencesOfString:secretPart withString:@"secret=***"];
KBLOG(@"[KBNetwork] sign source: %@", masked);
KBLOG(@"[KBNetwork] sign value: %@", sign ?: @"");
}
#endif
//
NSMutableDictionary<NSString *, NSString *> *headers =
[self.defaultHeaders mutableCopy] ?: [NSMutableDictionary dictionary];
@@ -202,6 +235,7 @@ autoShowBusinessError:YES
parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *,NSString *> *)headers
completion:(KBNetworkDataCompletion)completion {
[self getSignWithParare:parameters];
if (!self.isEnabled) {
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain
code:KBNetworkErrorDisabled
@@ -243,6 +277,7 @@ autoShowBusinessError:YES
completion:(KBNetworkCompletion)completion
{
NSLog(@"[KBNetworkManager] UPLOAD called, enabled=%d, path=%@", self.isEnabled, path);
[self getSignWithParare:@{}];
if (![self ensureEnabled:completion]) return nil;
NSString *urlString = [self buildURLStringWithPath:path];
@@ -330,6 +365,7 @@ autoShowBusinessError:YES
parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *, NSString *> *)headers
completion:(KBNetworkCompletion)completion {
[self getSignWithParare:parameters ?: @{}];
if (!fileURL || !fileURL.isFileURL) {
if (completion) {
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain