/*
* Copyright (c) 2023-2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "BridgePlugin.h"
#include <Foundation/Foundation.h>
#import <objc/message.h>
#import <objc/runtime.h>
#import "BridgeGCDTaskQueue.h"
#import "BridgePluginManager+internal.h"
#import "BridgeManagerHolder.h"
#import "ResultValue.h"
#include "base/log/log.h"
@interface BridgePlugin () {
BridgeType _bridgeType;
}
@property(nonatomic, strong) TaskOption* taskOptionInner;
@property(nonatomic, strong) NSString* bridgeNameInner;
@property(nonatomic, strong) BridgePluginManager* bridgeManagerInner;
@property(nonatomic, assign) BOOL isAvailable;
@end
@implementation BridgePlugin
#pragma mark - public method
- (instancetype)initBridgePlugin:(NSString* _Nonnull)bridgeName
instanceId:(int32_t)instanceId {
BridgePluginManager* bridgeManager = [BridgeManagerHolder getBridgePluginManager];
return [self initBridgePlugin:bridgeName bridgeManager:bridgeManager];
}
- (instancetype)initBridgePlugin:(NSString* _Nonnull)bridgeName
bridgeType:(BridgeType)type {
BridgePluginManager* bridgeManager = [BridgeManagerHolder getBridgePluginManager];
return [self initBridgePlugin:bridgeName bridgeManager:bridgeManager bridgeType:type taskOption:nil];
}
- (instancetype)initBridgePlugin:(NSString* _Nonnull)bridgeName
bridgeManager:(BridgePluginManager*)bridgeManager {
bridgeManager = [BridgeManagerHolder getBridgePluginManager];
return [self initBridgePlugin:bridgeName bridgeManager:bridgeManager bridgeType:JSON_TYPE taskOption:nil];
}
- (instancetype)initBridgePlugin:(NSString* _Nonnull)bridgeName
bridgeManager:(BridgePluginManager*)bridgeManager
bridgeType:(BridgeType)type {
bridgeManager = [BridgeManagerHolder getBridgePluginManager];
return [self initBridgePlugin:bridgeName bridgeManager:bridgeManager bridgeType:type taskOption:nil];
}
- (instancetype)initBridgePlugin:(NSString* _Nonnull)bridgeName
bridgeManager:(BridgePluginManager*)bridgeManager
bridgeType:(BridgeType)type
taskOption:(TaskOption*)taskOption {
self = [super init];
if (self) {
if (taskOption) {
self.taskOptionInner = taskOption;
}
self.bridgeNameInner = bridgeName;
_bridgeType = type;
self.bridgeManagerInner = [BridgeManagerHolder getBridgePluginManager];
if ([self checkBridgeInner]) {
[self.bridgeManager innerRegisterBridgePlugin:bridgeName bridgePlugin:self];
}
}
return self;
}
- (void)callMethod:(MethodData*)method {
if (!_isAvailable) {
LOGE("bridgePlugin is available!");
return;
}
__weak BridgePlugin* weakSelf = self;
if (self.type == JSON_TYPE) {
[self.bridgeManager platformCallMethod:self.bridgeName
methodName:method.methodName
param:method.parameter
reultValueCallback:(^(ResultValue* result) {
[weakSelf sendErrorCodeWithResult:result withMethodName:method.methodName];
})];
} else {
[self.bridgeManager platformCallMethodBinary:self.bridgeName
methodName:method.methodName
param:method.parameter
reultValueCallback:(^(ResultValue* result) {
[weakSelf sendErrorCodeWithResult:result withMethodName:method.methodName];
})];
}
}
- (id)callMethodSyncInner:(MethodData*)method {
ResultValue* resultValue = [[ResultValue alloc] init];
@try {
if (!_isAvailable) {
NSString* strCode = [NSString stringWithFormat:@"%d", BRIDGE_INVALID];
NSException* exception = [NSException exceptionWithName:strCode reason:BRIDGE_INVALID_MESSAGE userInfo:nil];
@throw exception;
}
if (self.type == JSON_TYPE) {
resultValue = [self.bridgeManager platformCallMethodInnerReult:self.bridgeName
methodName:method.methodName
param:method.parameter];
} else {
resultValue = [self.bridgeManager platformCallMethodBinaryInnerResult:self.bridgeName
methodName:method.methodName
param:method.parameter];
}
if (resultValue.errorCode != BRIDGE_ERROR_NO) {
NSString* strCode = [NSString stringWithFormat:@"%d", resultValue.errorCode];
NSException* exception = [NSException exceptionWithName:strCode
reason:resultValue.errorMessage
userInfo:nil];
@throw exception;
}
} @catch (NSException* exception) {
LOGE("bridge callMethodSyncInner catch");
[exception raise];
}
return resultValue.result;
}
- (id)callMethodSync:(NSString*)methodName parameters:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION {
NSMutableArray* objects = [NSMutableArray array];
va_list arguments;
if (firstObj) {
id eachObject = nil;
[objects addObject:firstObj];
va_start(arguments, firstObj);
while ((eachObject = va_arg(arguments, id))) {
[objects addObject:eachObject];
}
va_end(arguments);
}
MethodData* methodData = [[MethodData alloc] initMethodWithName:methodName
parameter:objects.copy];
return [self callMethodSyncInner:methodData];
}
- (void)sendErrorCodeWithResult:(ResultValue*)result withMethodName:(NSString*)methodName {
if (result) {
if (self.methodResult &&
[self.methodResult respondsToSelector:@selector(onError:errorCode:errorMessage:)])
{
[self.methodResult onError:methodName
errorCode:result.errorCode
errorMessage:result.errorMessage];
}
}
}
- (void)sendMessage:(id)data {
if (!_isAvailable) {
LOGE("bridgePlugin is available!");
return;
}
if (self.type == JSON_TYPE) {
[self.bridgeManager platformSendMessage:self.bridgeName data:data];
} else {
// BINARY_TYPE
if ([data isKindOfClass:[NSArray class]]) {
if (self.methodResult &&
[self.methodResult respondsToSelector:@selector(onError:errorCode:errorMessage:)]) {
[self.methodResult onError:@"please use BridgeArray"
errorCode:BRIDGE_DATA_ERROR
errorMessage:BRIDGE_DATA_ERROR_MESSAGE];
}
return;
}
[self.bridgeManager platformSendMessageBinary:self.bridgeName
data:data];
}
}
- (BOOL)isBridgeAvailable {
return _isAvailable;
}
- (BOOL)unRegister:(NSString*)bridgeName {
return [self.bridgeManager innerUnRegisterBridgePlugin:bridgeName];
}
- (BridgeType)type {
return _bridgeType;
}
- (TaskOption*)taskOption {
return _taskOptionInner;
}
- (BOOL)checkBridgeInner {
if (self.bridgeName && self.bridgeName.length != 0 && self.bridgeManager) {
return true;
}
return false;
}
- (NSString*)bridgeName {
return self.bridgeNameInner;
}
- (BridgePluginManager*)bridgeManager {
return self.bridgeManagerInner;
}
- (void)onPeerReady {}
@end