Flutter 跟 IOS 原生通信--UIKitView使用(二)

Flutter 跟 IOS 原生通信--数据传输(一)

以写一个iOS原生播放视频的view为例:

1、首先打开xcode的info.plist文件,添加io.flutter.embedded_views_preview设置为YES,如下图:


截屏2021-10-19 下午3.17.43.png

2、flutter添加 UiKitView,以下为futter部分全部代码:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class IosPlayer extends StatefulWidget {

  @override
  _IosPlayerState createState() => _IosPlayerState();
}

class _IosPlayerState extends State {
  @override
  Widget build(BuildContext context) {


    return Scaffold(
      appBar: AppBar(
        title: Center(
          child: Text('ios_player'),
        ),
      ),
      body: SafeArea(
        child: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.white,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Container(
                width: double.infinity,
                height: 270,
                child: _playerView(context),
              )
            ],
          ),
        ),
      ),
    );
  }

  Widget _playerView(context){
     if (Platform.isIOS){
       return UiKitView(
         viewType: 'plugins/player',
         onPlatformViewCreated:_onPlatformViewCreated,
         creationParams: {
           'url':'https://www.apple.com/105/media/cn/researchkit/2016/a63aa7d4_e6fd_483f_a59d_d962016c8093/films/carekit/researchkit-carekit-cn-20160321_848x480.mp4'
         },
         creationParamsCodec: new JSONMessageCodec(),
       );
     }
     return SizedBox();
  }

  Future _onPlatformViewCreated(int id) async {
    print("**********ok***********id="+id.toString());
  }
}

注意:creationParams字段是到iOS原生view的传值内容,是个map;
3、接下来在iOS原生部分,先创建要实现的view,代码如下:

.h

#import 
#import 
#import 
#import 
NS_ASSUME_NONNULL_BEGIN

@interface PlayerView : UIView
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject*)registrar;
@end

NS_ASSUME_NONNULL_END

.m

#import "PlayerView.h"

@interface PlayerView()
@property (nonatomic,strong) FlutterMethodChannel *channel;
@property (nonatomic,strong) AVPictureInPictureController *pipVC;
@property (nonatomic,strong) AVPlayer *avPlayer;
@property (nonatomic,strong) AVPlayerLayer *playerLayer;
@end
@implementation PlayerView
{
    NSString *_nowUrl;
}

- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject*)registrar
{
    self = [super init];
    if (self) {
        NSDictionary *dictionary = [NSDictionary dictionaryWithDictionary:args];
        _nowUrl = dictionary[@"url"];
        NSLog(@"==========dictionary:%@",dictionary);
        NSString *name = @"plugins";
        FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:name binaryMessenger:registrar.messenger];
        self.channel = channel;
        [registrar addMethodCallDelegate:self channel:channel];
        self.backgroundColor = [UIColor blackColor];
        [self initPlayer];
    }
    return self;
}

- (void)initPlayer{
    NSURL *url = [NSURL URLWithString:_nowUrl];
    @try {
        NSError *error = nil;
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionOrientationBack error:&error];
        [[AVAudioSession sharedInstance] setActive:YES error:&error];
    } @catch (NSException *exception) {
        NSLog(@"AvAudioSession发生错误");
    }
    self.avPlayer = [AVPlayer playerWithURL:url];
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    self.pipVC = [[AVPictureInPictureController alloc] initWithPlayerLayer:self.playerLayer];
    [self.layer addSublayer:self.playerLayer];
    self.pipVC.delegate = self;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
}

- (void)layoutSubviews{
    [super layoutSubviews];
    NSLog(@"bounds:width:%f,height:%f",self.bounds.size.width,self.bounds.size.height);
    self.playerLayer.frame = self.bounds;
    [self play];
}

- (void)addListen{
    __weak typeof(self) weakSelf = self;
    [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        NSLog(@"当前时间:%f",CMTimeGetSeconds(weakSelf.avPlayer.currentItem.currentTime));
        NSLog(@"总时间%f",CMTimeGetSeconds(weakSelf.avPlayer.currentItem.duration));
    }];
}

- (void)play{
    [self.avPlayer play];
}

- (void)pause{
    [self.avPlayer pause];
}

- (void)seekTo:(int)time{
    CMTime nextTime = CMTimeMakeWithSeconds(time/1000, 1.0);
    [self.avPlayer seekToTime:nextTime];
}

- (void)replacePlay:(NSString *)urlString{
    NSURL *url = [[NSURL alloc]initWithString:urlString];
    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];
    [self.avPlayer replaceCurrentItemWithPlayerItem:item];
}

- (void)startPiP{
    if ([AVPictureInPictureController isPictureInPictureSupported]) {
        if (self.pipVC == nil){
            self.pipVC = [[AVPictureInPictureController alloc]initWithPlayerLayer:self.playerLayer];
            self.pipVC.delegate = self;
        }
        if (self.pipVC.pictureInPictureActive == NO){
            [self.pipVC startPictureInPicture];
        }
    }
}

- (void)stopPip{
    if ([AVPictureInPictureController isPictureInPictureSupported]) {
        if (self.pipVC == nil){
            self.pipVC = [[AVPictureInPictureController alloc]initWithPlayerLayer:self.playerLayer];
            self.pipVC.delegate = self;
        }
        if (self.pipVC.pictureInPictureActive){
            [self.pipVC stopPictureInPicture];
        }
    }
}


+ (void)registerWithRegistrar:(nonnull NSObject *)registrar {
    
}

- (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController{
    
}

- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController{
    
}

- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController failedToStartPictureInPictureWithError:(NSError *)error{
    
}

- (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController{
    
}

- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController{
    
}

- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler{
    
}

@end

4、创建FlutterPlatformView,代码如下:

.h

#import 
#import 

NS_ASSUME_NONNULL_BEGIN

@interface PlayerPlatformView : NSObject
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject*)registrar;
@end

NS_ASSUME_NONNULL_END

.m

#import "PlayerPlatformView.h"
#import "PlayerView.h"

@interface PlayerPlatformView()
{
//这是要添加到flutter上的view,
    PlayerView *playerView;
}
@end
@implementation PlayerPlatformView

- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject*)registrar
{
    self = [super init];
    if (self) {
        playerView = [[PlayerView alloc]initWithFrame:frame viewIdentifier:viewId arguments:args registrar:registrar];
    }
    return self;
}

- (UIView*)view{
    return  playerView;
}
@end

5、创建FlutterPlatformViewFactory,代码如下:

.h

#import 
#import 
NS_ASSUME_NONNULL_BEGIN

@interface PlayerFactory : NSObject
- (instancetype)initWith:(NSObject*)registrar;
@end

NS_ASSUME_NONNULL_END

.m

#import "PlayerFactory.h"
#import "PlayerPlatformView.h"
@interface PlayerFactory()
{
    id _registrar;
}

@end
@implementation PlayerFactory
- (instancetype)initWith:(NSObject*)registrar{
    self = [super init];
        if (self) {
            _registrar = registrar;
        }
        return self;
}

//实现协议方法,flutter根据widget自动计算出iOS的frame,
//自动生成的viewId和flutter那边对应,flutter传的参数args
- (NSObject*)createWithFrame:(CGRect)frame
                                   viewIdentifier:(int64_t)viewId
                                        arguments:(id _Nullable)args
{
    NSLog(@"====---f--==%@",NSStringFromCGRect(frame));
    NSLog(@"====-----==%lld",viewId);
    NSLog(@"=======%@",args);
    return [[PlayerPlatformView alloc] initWithFrame:frame viewIdentifier:viewId arguments:args registrar:_registrar];
}

//关于编码格式一定要和flutter那边统一,并且和传递的参数类型匹配,
//如果flutter传递的是json,map,编码必须是JSONMessageCodec,
//flutter传递的是string,编码必须是Stringcodec,否则会出错,加载不了view
- (NSObject*)createArgsCodec
{
    return  [[FlutterJSONMessageCodec alloc] init];
}

@end

6、创建FlutterPlugin,代码如下:

.h

#import 
#import 
NS_ASSUME_NONNULL_BEGIN

@interface PlayerPlugin : NSObject
//+ (void)registerWithRegistrar:(NSObject*)registrar;
@end

NS_ASSUME_NONNULL_END

.m

#import "PlayerPlugin.h"
#import "PlayerFactory.h"
@implementation PlayerPlugin


+ (void)registerWithRegistrar:(NSObject*)registrar
{
    PlayerFactory *fc = [[PlayerFactory alloc] initWith:registrar];
    [registrar registerViewFactory:fc withId:@"plugins/player"];
}

@end

此处的plugins/player对应UiKitView的viewType

7、最后在didFinishLaunchingWithOptions方法里边初始化,代码如下:

[PlayerPlugin registerWithRegistrar:[_flutterVC registrarForPlugin:@"ViewPlugin"]];

你可能感兴趣的:(Flutter 跟 IOS 原生通信--UIKitView使用(二))