2026-05-22 17:35:49 +08:00

235 lines
8.3 KiB
Plaintext

#import "TGFlutterPagPlatformView.h"
#import "TGFlutterPagDownloadManager.h"
#import <libpag/PAGFile.h>
#import <libpag/PAGImage.h>
#import <libpag/PAGScaleMode.h>
#import <libpag/PAGView.h>
#import <UIKit/UIKit.h>
@interface TGFlutterPagPlatformView : NSObject <FlutterPlatformView, PAGViewListener>
@property(nonatomic, strong) PAGView* pagView;
@property(nonatomic, weak) NSObject<FlutterPluginRegistrar>* registrar;
@end
@implementation TGFlutterPagPlatformView
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id)arguments
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_registrar = registrar;
_pagView = [[PAGView alloc] initWithFrame:frame];
_pagView.backgroundColor = UIColor.clearColor;
_pagView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_pagView setScaleMode:PAGScaleModeLetterBox];
[_pagView addListener:self];
[self configureWithArguments:arguments];
}
return self;
}
- (UIView*)view {
return _pagView;
}
- (void)configureWithArguments:(id)arguments {
if (![arguments isKindOfClass:NSDictionary.class]) {
return;
}
NSDictionary* params = arguments;
int repeatCount = 1;
id repeatValue = params[@"repeatCount"];
if ([repeatValue respondsToSelector:@selector(intValue)]) {
repeatCount = [repeatValue intValue];
}
double initProgress = 0.0;
id progressValue = params[@"initProgress"];
if ([progressValue respondsToSelector:@selector(doubleValue)]) {
initProgress = [progressValue doubleValue];
}
BOOL autoPlay = NO;
id autoPlayValue = params[@"autoPlay"];
if ([autoPlayValue respondsToSelector:@selector(boolValue)]) {
autoPlay = [autoPlayValue boolValue];
}
NSDictionary<NSString*, NSData*>* imageReplacementsByName = [self imageReplacementsByNameFromParams:params];
[_pagView setRepeatCount:repeatCount];
[_pagView setProgress:initProgress];
NSString* assetName = [self nonEmptyString:params[@"assetName"]];
if (assetName.length > 0) {
NSString* package = [self nonEmptyString:params[@"package"]];
NSString* assetPath = [self assetPathForName:assetName package:package];
[self loadPath:assetPath initProgress:initProgress autoPlay:autoPlay imageReplacementsByName:imageReplacementsByName];
return;
}
NSString* url = [self nonEmptyString:params[@"url"]];
if (url.length > 0) {
__weak typeof(self) weakSelf = self;
[TGFlutterPagDownloadManager download:url completionHandler:^(NSData* data, NSError* error) {
if (data == nil || data.length == 0) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadData:data initProgress:initProgress autoPlay:autoPlay imageReplacementsByName:imageReplacementsByName];
});
}];
return;
}
id bytesData = params[@"bytesData"];
if ([bytesData isKindOfClass:FlutterStandardTypedData.class]) {
FlutterStandardTypedData* typedData = bytesData;
if (typedData.type == FlutterStandardDataTypeUInt8) {
[self loadData:typedData.data initProgress:initProgress autoPlay:autoPlay imageReplacementsByName:imageReplacementsByName];
}
}
}
- (NSString*)nonEmptyString:(id)value {
if (![value isKindOfClass:NSString.class]) {
return nil;
}
NSString* text = [(NSString*)value stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
return text.length > 0 ? text : nil;
}
- (NSString*)assetPathForName:(NSString*)assetName package:(NSString*)package {
NSString* resourcePath = nil;
if (package.length > 0) {
resourcePath = [_registrar lookupKeyForAsset:assetName fromPackage:package];
} else {
resourcePath = [_registrar lookupKeyForAsset:assetName];
}
return [[NSBundle mainBundle] pathForResource:resourcePath ofType:nil];
}
- (void)loadPath:(NSString*)path initProgress:(double)initProgress autoPlay:(BOOL)autoPlay imageReplacementsByName:(NSDictionary<NSString*, NSData*>*)imageReplacementsByName {
if (path.length == 0) {
return;
}
if (imageReplacementsByName.count > 0) {
PAGFile* file = [PAGFile Load:path];
[self applyImageReplacementsByName:imageReplacementsByName toFile:file];
[self setFile:file initProgress:initProgress autoPlay:autoPlay];
return;
}
if (![_pagView setPath:path]) {
return;
}
[_pagView setProgress:initProgress];
[_pagView flush];
if (autoPlay) {
[_pagView play];
}
}
- (void)loadData:(NSData*)data initProgress:(double)initProgress autoPlay:(BOOL)autoPlay imageReplacementsByName:(NSDictionary<NSString*, NSData*>*)imageReplacementsByName {
if (data == nil || data.length == 0) {
return;
}
PAGFile* file = [PAGFile Load:data.bytes size:data.length];
[self applyImageReplacementsByName:imageReplacementsByName toFile:file];
[self setFile:file initProgress:initProgress autoPlay:autoPlay];
}
- (void)setFile:(PAGFile*)file initProgress:(double)initProgress autoPlay:(BOOL)autoPlay {
if (file == nil || file.width <= 0 || file.height <= 0) {
return;
}
[_pagView setComposition:file];
[_pagView setProgress:initProgress];
[_pagView flush];
if (autoPlay) {
[_pagView play];
}
}
- (NSDictionary<NSString*, NSData*>*)imageReplacementsByNameFromParams:(NSDictionary*)params {
id raw = params[@"imageReplacementsByName"];
if (![raw isKindOfClass:NSDictionary.class]) {
return @{};
}
NSMutableDictionary<NSString*, NSData*>* result = [[NSMutableDictionary alloc] init];
[(NSDictionary*)raw enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
if (![key isKindOfClass:NSString.class]) {
return;
}
NSString* layerName = [(NSString*)key stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if (layerName.length == 0) {
return;
}
NSData* data = nil;
if ([value isKindOfClass:FlutterStandardTypedData.class]) {
FlutterStandardTypedData* typedData = value;
if (typedData.type == FlutterStandardDataTypeUInt8) {
data = typedData.data;
}
} else if ([value isKindOfClass:NSData.class]) {
data = value;
}
if (data.length > 0) {
result[layerName] = data;
}
}];
return result;
}
- (void)applyImageReplacementsByName:(NSDictionary<NSString*, NSData*>*)imageReplacementsByName toFile:(PAGFile*)file {
if (file == nil || imageReplacementsByName == nil || imageReplacementsByName.count == 0) {
return;
}
[imageReplacementsByName enumerateKeysAndObjectsUsingBlock:^(NSString* layerName, NSData* data, BOOL* stop) {
if (![layerName isKindOfClass:NSString.class] || layerName.length == 0 ||
![data isKindOfClass:NSData.class] || data.length == 0) {
return;
}
PAGImage* image = [PAGImage FromBytes:data.bytes size:data.length];
if (image == nil) {
return;
}
[image setScaleMode:PAGScaleModeZoom];
[file replaceImageByName:layerName data:image];
}];
}
- (void)dealloc {
[_pagView removeListener:self];
[_pagView stop];
[_pagView setComposition:nil];
}
@end
@implementation TGFlutterPagPlatformViewFactory {
__weak NSObject<FlutterPluginRegistrar>* _registrar;
}
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_registrar = registrar;
}
return self;
}
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
return FlutterStandardMessageCodec.sharedInstance;
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id)args {
return [[TGFlutterPagPlatformView alloc] initWithFrame:frame
viewIdentifier:viewId
arguments:args
registrar:_registrar];
}
@end