1. 下载库
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios
2. 进入文件夹
cd ijkplayer-ios
3. 切换分支
git checkout -B latest k0.8.8
4.运行ios初始化脚本
./init-ios.sh
5. 更改文件
打开项目ijkplayer-ios => iOS => IJKMediaPlayer
由于ijkplayer 第一次加载播放器时卡主线程, 是因为内部源码问题, 需要更改源文件
- 更改文件: IJKSDLGLView.m,
- 文件位置: ijkplayer-ios/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/iOS/IJKSDLGLView.m
- 更改后内容如下
- 首先,增加个只在主线程操作的方法,这个方法里面就是先判断当前是否在主线程,如果是就直接执行,否则同步切换到主队列进行执行。
static void IJKHanleInMainThread(dispatch_block_t mainThreadblock) {
if ([NSThread currentThread] == [NSThread mainThread]){
mainThreadblock();
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
mainThreadblock();
});
}
}
- 其次将方法- (BOOL)isApplicationActive里面改成这样:
__block UIApplicationState appState = 0;
IJKHanleInMainThread(^{
appState = [UIApplication sharedApplication].applicationState;
});
- 将方法- (void)displayInternal: (SDL_VoutOverlay *) overlay里面改成这样
IJKHanleInMainThread(^{
[[self eaglLayer] setContentsScale:_scaleFactor];
});
IJKHanleInMainThread(^{
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
});
完整源码放在文章最后
IJKAudioKit文件
- 文件位置: ijkplayer-ios/ios/IJKMediaPlayer/IJKMediaPlayer/IJKAudioKit.m
返回值报错,将IJKAudioKit.h及IJKAudioKit.m中 setActive中的返回值Bool改为void
- (void)setActive:(BOOL)active;
6.去掉对armv7支持
由于apple现在不允许32位的应用上架AppStore了,弱化了对armv7的处理,执行 ./compile-ffmpeg.sh all会报错
修改compile-ffmpeg.sh
和 compile-openssl.sh
两个文件,去掉对armv7的支持
原来:
FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64"
现在:
FF_ALL_ARCHS_IOS8_SDK="arm64 i386 x86_64"
7.修改真机模拟器库无法合并问题
如果不修改, 打出包后, 会出现真机模拟器库无法合并,报错:have the same architectures (arm64) and can't be in the same fat output file
XCode12之前:
编译模拟器静态库支持i386 x86_64两架构
编译真机静态库支持armv7 arm64两架构
使用lipo -create -output命令可以将两个库合并成一个支持模拟器和真机i386 x86_64 armv7 arm64四种架构的胖子库。
XCode12编译的模拟器静态库也支持了arm64,导致出现真机库和模拟器库不能合并的问题。
设置Build Setting --> Excluded Architectures --> Debug --> 添加上 arm64
设置Build Setting --> Excluded Architectures --> Release --> 添加上 arm64
出现的原因是XCode12 编译的模拟器库新增支持架构arm64。
将模拟器的arm64给排除出去即可。
8.添加https 支持
最后会生成支持 https 的静态文件 libcrypto.a 和 libssl.a,
- 获取 openssl 并初始化
./init-ios-openssl.sh
cd iOS
- 在模块文件中添加一行配置 以启用 openssl 组件
echo 'export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-openssl"' >> ../config/module.sh
编译
# 清除操作
./compile-openssl.sh clean
./compile-ffmpeg.sh clean
# 编译openssl,生成 `libcrypto.a` 和 `libssl.a`,如果不需要https可以跳过这一步
./compile-openssl.sh all
# 编译ffmpeg
./compile-ffmpeg.sh all
10. 打包framework
大家会发现除了 IJKMediaFramework 这个 target, 还有一个叫 IJKMediaFrameworkWithSSL, 但是不推荐使用这个, 因为大部分基于 ijkplayer 的第三方框架都是使用的前者, 你把后者导入项目还是会报找不到包的错误, 就算你要支持 https 也推荐使用前者, 然后按照上一步添加 openssl 即可支持
-
设置工程的 scheme, 选择eidt scheme如图
-
编辑build configuration为release
设置好 scheme 后, 分别选择真机和模拟器进行编译(其实就是run)
12. 查看编译后的包
正常情况下查看如下
选中products => IJKMedisFramework => show in finder
查看真机与模拟器的
Xcode13 后 Products 目录可能显示不出来, 显示方法
首先打开项目,然后进入到你的项目目录并打开project.pbxproj文件
1、show in Finder 找到项目在电脑上的位置
2、右键点击xxx.xcodeproj -> 选择显示包内容
3、右键点击project.pbxproj -> 选择Xcode等工具打开文件
搜索productRefGroup
关键字
搜索结果可能有多个,每个项目的键值不一样具体看自己的项目。
注意看productRefGroup的注释 为/* Products */ 才是我们要修改的
mainGroup = ACA41EDA27868EE700DFCFA8;
productRefGroup = ACA41EE427868EE700DFCFA8 /* Products */;
将上面 mainGroup 对应的值复制给 productRefGroup的值,如下:
mainGroup = ACA41EDA27868EE700DFCFA8;
productRefGroup = ACA41EDA27868EE700DFCFA8 /* Products */;
保存 project.pbxproj文件,Xcode将自动刷新,这时候你想见的 Products 目录就出现了。
11. 合并IJKMediaFramework
命令
lipo -create 真机framework路径 模拟器framework路径 -output 合并的文件路径
例如
lipo -create Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework -output IJKMediaFramework
注意: lipo -create "真机版本路径" "模拟器版本路径" -output "合并后的文件路径" 合并后的路径你需要给出名字IJKMediaFramework, 不然会合并失败 , 一定要带名字
将生成后的IJKMediaFramework直接替换掉Release-iphoneos中的IJKMediaFramework就行
替换后这个就是需要的framework
12. 使用
将上面的包拖入项目即可使用
参考文章:
https://www.jianshu.com/p/6ec0ec0244e2
https://github.com/zdhgithub/ijkplayer123/blob/master/IJKSDLGLView_mainThread.m
https://github.com/Zhangyanshen/ijkplayer-ios-demo#
https://www.jianshu.com/p/59aff611dacd
https://zhuanlan.zhihu.com/p/444825777
https://blog.csdn.net/lrbtony/article/details/123382820
https://www.jianshu.com/p/3b9187b91607
代码. IJKSDLGLView.m
/*
* IJKSDLGLView.m
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* based on https://github.com/kolyvan/kxmovie
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "IJKSDLGLView.h"
#include "ijksdl/ijksdl_timer.h"
#include "ijksdl/iOS/ijksdl_ios.h"
#include "ijksdl/ijksdl_gles2.h"
typedef NS_ENUM(NSInteger, IJKSDLGLViewApplicationState) {
IJKSDLGLViewApplicationUnknownState = 0,
IJKSDLGLViewApplicationForegroundState = 1,
IJKSDLGLViewApplicationBackgroundState = 2
};
@interface IJKSDLGLView()
@property(atomic,strong) NSRecursiveLock *glActiveLock;
@property(atomic) BOOL glActivePaused;
@end
@implementation IJKSDLGLView {
EAGLContext *_context;
GLuint _framebuffer;
GLuint _renderbuffer;
GLint _backingWidth;
GLint _backingHeight;
int _frameCount;
int64_t _lastFrameTime;
IJK_GLES2_Renderer *_renderer;
int _rendererGravity;
BOOL _isRenderBufferInvalidated;
int _tryLockErrorCount;
BOOL _didSetupGL;
BOOL _didStopGL;
BOOL _didLockedDueToMovedToWindow;
BOOL _shouldLockWhileBeingMovedToWindow;
NSMutableArray *_registeredNotifications;
IJKSDLGLViewApplicationState _applicationState;
}
@synthesize isThirdGLView = _isThirdGLView;
@synthesize scaleFactor = _scaleFactor;
@synthesize fps = _fps;
#warning change add https://blog.csdn.net/mlcldh/article/details/101155942?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-4-101155942.nonecase&utm_term=ijkplayer%20%E4%B8%BB%E7%BA%BF%E7%A8%8B%E9%97%AE%E9%A2%98
static void IJKHanleInMainThread(dispatch_block_t mainThreadblock) {
if ([NSThread currentThread] == [NSThread mainThread]){
mainThreadblock();
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
mainThreadblock();
});
}
}
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_tryLockErrorCount = 0;
_shouldLockWhileBeingMovedToWindow = YES;
self.glActiveLock = [[NSRecursiveLock alloc] init];
_registeredNotifications = [[NSMutableArray alloc] init];
[self registerApplicationObservers];
_didSetupGL = NO;
if ([self isApplicationActive] == YES)
[self setupGLOnce];
}
return self;
}
- (void)willMoveToWindow:(UIWindow *)newWindow
{
if (!_shouldLockWhileBeingMovedToWindow) {
[super willMoveToWindow:newWindow];
return;
}
if (newWindow && !_didLockedDueToMovedToWindow) {
[self lockGLActive];
_didLockedDueToMovedToWindow = YES;
}
[super willMoveToWindow:newWindow];
}
- (void)didMoveToWindow
{
[super didMoveToWindow];
if (self.window && _didLockedDueToMovedToWindow) {
[self unlockGLActive];
_didLockedDueToMovedToWindow = NO;
}
}
- (BOOL)setupEAGLContext:(EAGLContext *)context
{
glGenFramebuffers(1, &_framebuffer);
glGenRenderbuffers(1, &_renderbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x\n", status);
return NO;
}
GLenum glError = glGetError();
if (GL_NO_ERROR != glError) {
NSLog(@"failed to setup GL %x\n", glError);
return NO;
}
return YES;
}
- (CAEAGLLayer *)eaglLayer
{
return (CAEAGLLayer*) self.layer;
}
- (BOOL)setupGL
{
if (_didSetupGL)
return YES;
CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
_scaleFactor = [[UIScreen mainScreen] scale];
if (_scaleFactor < 0.1f)
_scaleFactor = 1.0f;
[eaglLayer setContentsScale:_scaleFactor];
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (_context == nil) {
NSLog(@"failed to setup EAGLContext\n");
return NO;
}
EAGLContext *prevContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:_context];
_didSetupGL = NO;
if ([self setupEAGLContext:_context]) {
NSLog(@"OK setup GL\n");
_didSetupGL = YES;
}
[EAGLContext setCurrentContext:prevContext];
return _didSetupGL;
}
- (BOOL)setupGLOnce
{
if (_didSetupGL)
return YES;
if (![self tryLockGLActive])
return NO;
BOOL didSetupGL = [self setupGL];
[self unlockGLActive];
return didSetupGL;
}
- (BOOL)isApplicationActive {
switch (_applicationState) {
case IJKSDLGLViewApplicationForegroundState:
return YES;
case IJKSDLGLViewApplicationBackgroundState:
return NO;
default: {
#warning change
__block UIApplicationState appState = 0;
IJKHanleInMainThread(^{
appState = [UIApplication sharedApplication].applicationState;
});
// UIApplicationState appState = [UIApplication sharedApplication].applicationState;
switch (appState) {
case UIApplicationStateActive:
return YES;
case UIApplicationStateInactive:
case UIApplicationStateBackground:
default:
return NO;
}
}
}
}
- (void)dealloc
{
[self lockGLActive];
_didStopGL = YES;
EAGLContext *prevContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:_context];
IJK_GLES2_Renderer_reset(_renderer);
IJK_GLES2_Renderer_freeP(&_renderer);
if (_framebuffer) {
glDeleteFramebuffers(1, &_framebuffer);
_framebuffer = 0;
}
if (_renderbuffer) {
glDeleteRenderbuffers(1, &_renderbuffer);
_renderbuffer = 0;
}
glFinish();
[EAGLContext setCurrentContext:prevContext];
_context = nil;
[self unregisterApplicationObservers];
[self unlockGLActive];
}
- (void)setScaleFactor:(CGFloat)scaleFactor
{
_scaleFactor = scaleFactor;
[self invalidateRenderBuffer];
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.window.screen != nil) {
_scaleFactor = self.window.screen.scale;
}
[self invalidateRenderBuffer];
}
- (void)setContentMode:(UIViewContentMode)contentMode
{
[super setContentMode:contentMode];
switch (contentMode) {
case UIViewContentModeScaleToFill:
_rendererGravity = IJK_GLES2_GRAVITY_RESIZE;
break;
case UIViewContentModeScaleAspectFit:
_rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT;
break;
case UIViewContentModeScaleAspectFill:
_rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL;
break;
default:
_rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT;
break;
}
[self invalidateRenderBuffer];
}
- (BOOL)setupRenderer: (SDL_VoutOverlay *) overlay
{
if (overlay == nil)
return _renderer != nil;
if (!IJK_GLES2_Renderer_isValid(_renderer) ||
!IJK_GLES2_Renderer_isFormat(_renderer, overlay->format)) {
IJK_GLES2_Renderer_reset(_renderer);
IJK_GLES2_Renderer_freeP(&_renderer);
_renderer = IJK_GLES2_Renderer_create(overlay);
if (!IJK_GLES2_Renderer_isValid(_renderer))
return NO;
if (!IJK_GLES2_Renderer_use(_renderer))
return NO;
IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight);
}
return YES;
}
- (void)invalidateRenderBuffer
{
NSLog(@"invalidateRenderBuffer\n");
[self lockGLActive];
_isRenderBufferInvalidated = YES;
if ([[NSThread currentThread] isMainThread]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
if (_isRenderBufferInvalidated)
[self display:nil];
});
} else {
[self display:nil];
}
[self unlockGLActive];
}
- (void) display_pixels: (IJKOverlay *) overlay {
return;
}
- (void)display: (SDL_VoutOverlay *) overlay
{
if (_didSetupGL == NO)
return;
if ([self isApplicationActive] == NO)
return;
if (![self tryLockGLActive]) {
if (0 == (_tryLockErrorCount % 100)) {
NSLog(@"IJKSDLGLView:display: unable to tryLock GL active: %d\n", _tryLockErrorCount);
}
_tryLockErrorCount++;
return;
}
_tryLockErrorCount = 0;
if (_context && !_didStopGL) {
EAGLContext *prevContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:_context];
[self displayInternal:overlay];
[EAGLContext setCurrentContext:prevContext];
}
[self unlockGLActive];
}
// NOTE: overlay could be NULl
- (void)displayInternal: (SDL_VoutOverlay *) overlay
{
if (![self setupRenderer:overlay]) {
if (!overlay && !_renderer) {
NSLog(@"IJKSDLGLView: setupDisplay not ready\n");
} else {
NSLog(@"IJKSDLGLView: setupDisplay failed\n");
}
return;
}
#warning change
IJKHanleInMainThread(^{
[[self eaglLayer] setContentsScale:_scaleFactor];
});
// [[self eaglLayer] setContentsScale:_scaleFactor];
if (_isRenderBufferInvalidated) {
NSLog(@"IJKSDLGLView: renderbufferStorage fromDrawable\n");
_isRenderBufferInvalidated = NO;
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
#warning change
IJKHanleInMainThread(^{
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
});
// [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight);
}
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
glViewport(0, 0, _backingWidth, _backingHeight);
if (!IJK_GLES2_Renderer_renderOverlay(_renderer, overlay))
ALOGE("[EGL] IJK_GLES2_render failed\n");
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER];
int64_t current = (int64_t)SDL_GetTickHR();
int64_t delta = (current > _lastFrameTime) ? current - _lastFrameTime : 0;
if (delta <= 0) {
_lastFrameTime = current;
} else if (delta >= 1000) {
_fps = ((CGFloat)_frameCount) * 1000 / delta;
_frameCount = 0;
_lastFrameTime = current;
} else {
_frameCount++;
}
}
#pragma mark AppDelegate
- (void) lockGLActive
{
[self.glActiveLock lock];
}
- (void) unlockGLActive
{
[self.glActiveLock unlock];
}
- (BOOL) tryLockGLActive
{
if (![self.glActiveLock tryLock])
return NO;
/*-
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive &&
[UIApplication sharedApplication].applicationState != UIApplicationStateInactive) {
[self.appLock unlock];
return NO;
}
*/
if (self.glActivePaused) {
[self.glActiveLock unlock];
return NO;
}
return YES;
}
- (void)toggleGLPaused:(BOOL)paused
{
[self lockGLActive];
if (!self.glActivePaused && paused) {
if (_context != nil) {
EAGLContext *prevContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:_context];
glFinish();
[EAGLContext setCurrentContext:prevContext];
}
}
self.glActivePaused = paused;
[self unlockGLActive];
}
- (void)registerApplicationObservers
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[_registeredNotifications addObject:UIApplicationWillEnterForegroundNotification];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[_registeredNotifications addObject:UIApplicationDidBecomeActiveNotification];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive)
name:UIApplicationWillResignActiveNotification
object:nil];
[_registeredNotifications addObject:UIApplicationWillResignActiveNotification];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[_registeredNotifications addObject:UIApplicationDidEnterBackgroundNotification];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate)
name:UIApplicationWillTerminateNotification
object:nil];
[_registeredNotifications addObject:UIApplicationWillTerminateNotification];
}
- (void)unregisterApplicationObservers
{
for (NSString *name in _registeredNotifications) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:name
object:nil];
}
}
- (void)applicationWillEnterForeground
{
NSLog(@"IJKSDLGLView:applicationWillEnterForeground: %d", (int)[UIApplication sharedApplication].applicationState);
[self setupGLOnce];
_applicationState = IJKSDLGLViewApplicationForegroundState;
[self toggleGLPaused:NO];
}
- (void)applicationDidBecomeActive
{
NSLog(@"IJKSDLGLView:applicationDidBecomeActive: %d", (int)[UIApplication sharedApplication].applicationState);
[self setupGLOnce];
[self toggleGLPaused:NO];
}
- (void)applicationWillResignActive
{
NSLog(@"IJKSDLGLView:applicationWillResignActive: %d", (int)[UIApplication sharedApplication].applicationState);
[self toggleGLPaused:YES];
glFinish();
}
- (void)applicationDidEnterBackground
{
NSLog(@"IJKSDLGLView:applicationDidEnterBackground: %d", (int)[UIApplication sharedApplication].applicationState);
_applicationState = IJKSDLGLViewApplicationBackgroundState;
[self toggleGLPaused:YES];
glFinish();
}
- (void)applicationWillTerminate
{
NSLog(@"IJKSDLGLView:applicationWillTerminate: %d", (int)[UIApplication sharedApplication].applicationState);
[self toggleGLPaused:YES];
}
#pragma mark snapshot
- (UIImage*)snapshot
{
[self lockGLActive];
UIImage *image = [self snapshotInternal];
[self unlockGLActive];
return image;
}
- (UIImage*)snapshotInternal
{
if (isIOS7OrLater()) {
return [self snapshotInternalOnIOS7AndLater];
} else {
return [self snapshotInternalOnIOS6AndBefore];
}
}
- (UIImage*)snapshotInternalOnIOS7AndLater
{
if (CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
return nil;
}
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
// Render our snapshot into the image context
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
// Grab the image from the context
UIImage *complexViewImage = UIGraphicsGetImageFromCurrentImageContext();
// Finish using the context
UIGraphicsEndImageContext();
return complexViewImage;
}
- (UIImage*)snapshotInternalOnIOS6AndBefore
{
EAGLContext *prevContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:_context];
GLint backingWidth, backingHeight;
// Bind the color renderbuffer used to render the OpenGL ES view
// If your application only creates a single color renderbuffer which is already bound at this point,
// this call is redundant, but it is needed if you're dealing with multiple renderbuffers.
// Note, replace "viewRenderbuffer" with the actual name of the renderbuffer object defined in your class.
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
// Get the size of the backing CAEAGLLayer
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;
NSInteger dataLength = width * height * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
// Read pixel data from the framebuffer
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels((int)x, (int)y, (int)width, (int)height, GL_RGBA, GL_UNSIGNED_BYTE, data);
// Create a CGImage with the pixel data
// If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel
// otherwise, use kCGImageAlphaPremultipliedLast
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
[EAGLContext setCurrentContext:prevContext];
// OpenGL ES measures data in PIXELS
// Create a graphics context with the target size measured in POINTS
UIGraphicsBeginImageContext(CGSizeMake(width, height));
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
// UIKit coordinate system is upside down to GL/Quartz coordinate system
// Flip the CGImage by rendering it to the flipped bitmap context
// The size of the destination area is measured in POINTS
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, width, height), iref);
// Retrieve the UIImage from the current context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Clean up
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
return image;
}
- (void)setShouldLockWhileBeingMovedToWindow:(BOOL)shouldLockWhileBeingMovedToWindow
{
_shouldLockWhileBeingMovedToWindow = shouldLockWhileBeingMovedToWindow;
}
@end
打包是出现真机无法打包, 模拟器可以打, 是因为我把arm64写错了