0、
最简单的一步:
注意!!!这个Architectures要加一个
Architectures -> valid architecture
添加一个 x86_64
1、更改platform
However, you may need to manually exclude other content. To do this, go to the Frameworks, Libraries, and Embedded Content list under the General tab for your iOS target. Then select iOS as the platform setting for the item. This setting excludes the item from the Mac version of your app.
Extention 需要舍弃
2、使用系统提供的宏来处理不兼容的代码
if frameworks or API that are unavailable to the Mac version of your app. To remedy this problem, find the code that doesn’t compile, and enclose it as shown here:
注意,这个宏很重要,macOS不兼容代码都可以搁这里边
#if !TARGET_OS_MACCATALYST
// Code to exclude from Mac.
#endif
另外,也可以这么干,macOS代码可以搁这里边(与上边相比去掉了 ! )
#if TARGET_OS_MACCATALYST
// Code to exclude from iOS .
#endif
3、一些无法编译的第三方
Showing All Errors Only
In /Users/XXXXXX/IJKMediaFramework.framework/IJKMediaFramework(IJKMediaPlayback.o), building for Mac Catalyst, but linking in object file built for iOS Simulator, for architecture x86_64
解决方法:
找到这个IJKMediaFramework在项目中引用的地方,
#if !TARGET_OS_MACCATALYST
目标framework
#endif
之后需要解决报错信息,方法同上
4、
Showing All Errors Only
Undefined symbol: OBJC_CLASS$_ALBBSDK
解决方法同3(全局搜索 "ALBBSDK",屏蔽处理)
5、
LSSupportsOpeningDocumentsInPlace = NO' is not supported on macOS. Either remove the entry or set it to YES, and also ensure that the application does open documents in place on macOS.
解决方案:新建target
[XCode使用四:XCode工程中创建多个Targets]https://blog.csdn.net/hitfyb/article/details/50875657
19.10.22 程序编译成功!!
上边这些应该是都能遇到的问题,之后仍然有许多问题需要解决,大家加油。
如果使用了 pod
建议新建target,pod配置文件根据target配置
可能遇到的问题:
- 与iOS不同,所有在mac上运行的bundle都需要签名(sign)。
解决步骤:点击 Pod Target 里 "Signing & Capabilities"中选择一个Team
上传商店遇到这个问题
ITMS-90284: Invalid Code Signing- The executable 'XXX.app/Contents/Frameworks/XXX.framework/Versions/A/Resources/XX.bundle' must be signed with the certificate that is contained in the provisioning profile.
需要在Bundle的Sign界面下的Signing Certificate中选取Sign to Run Locally。
以上解决方法参考Mac Catalyst 初步体验+排坑
2.pod中的三方使用 UIWebview等mac catalyst不支持的api,移除掉或者屏蔽掉,或者干脆不引用(pod配置文件中配置),注意, 执行pod install之后1中的配置修改会被抹掉 ,需要重新配置
关于优化
更像macOS App
Optimizing Your iPad App for Mac
Mac catalyst 支持的UIKit 库列表
官方教程,可以下载Demo做一下参考
UIKit Catalog: Creating and Customizing Views and Controls
添加状态栏菜单 以及 快捷键
Adding Menus and Shortcuts to the Menu Bar and User Interface.
示例代码(OC),官方给的Demo使用Swift,请自行查阅
在 AppDelegate中重写这个方法: buildMenuWithBuilder
-(void)buildMenuWithBuilder:(id<UIMenuBuilder>)builder{
//插入已存在menu下
//无快捷键
UICommand * fileMenuCommend = [UICommand commandWithTitle:@"继续皮" image:nil action:@selector(jixuOpenAction) propertyList:nil];
//有快捷键
UIKeyCommand * openMenuCommend = [UIKeyCommand commandWithTitle:@"皮一下" image:nil action:@selector(openAction) input:@"O" modifierFlags:UIKeyModifierCommand propertyList:nil];//注意两个action不能一样
UIMenu * openMenu = [UIMenu menuWithTitle:@"" image:nil identifier:@"com.example.apple-samplecode.menus.openMenu" options:UIMenuOptionsDisplayInline children:@[openMenuCommend,fileMenuCommend]];
[builder insertChildMenu:openMenu atStartOfMenuForIdentifier:UIMenuFile];
//添加新的menu
UICommand * cityCommend = [UICommand commandWithTitle:@"青岛" image:nil action:@selector(openActionP) propertyList:@"青岛"];
UIKeyCommand * cityMenuCommend = [UIKeyCommand commandWithTitle:@"济南" image:nil action:@selector(openActionD) input:@"P" modifierFlags:UIKeyModifierCommand propertyList:@"济南"];
UIMenu * cityMenu = [UIMenu menuWithTitle:@"城市" image:nil identifier:@"com.example.apple-samplecode.menus.cityMenu" options:@[] children:@[cityCommend,cityMenuCommend]];
[builder insertSiblingMenu:cityMenu afterMenuForIdentifier:UIMenuFile];//添加到文件菜单之后
}
-(void)openAction{
NSLog(@"openAction");
}
-(void) jixuOpenAction{
NSLog(@"openAction");
}
在视图中检测鼠标的指针(位置)
使用UIHoverGestureRecognizer
To detect when the user moves the pointer over a view in your app, add a
UIHoverGestureRecognizer to that view.
//创建一个手势,并添加到view上
let hover = UIHoverGestureRecognizer(target: self, action: #selector(hovering(_:)))
button.addGestureRecognizer(hover)
//手势触发的方法
@objc
func hovering(_ recognizer: UIHoverGestureRecognizer) {
switch recognizer.state {
case .began, .changed:
button.titleLabel?.textColor = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
case .ended:
button.titleLabel?.textColor = UIColor.link
default:
break
}
}
//OC代码
UIHoverGestureRecognizer * hover = [[UIHoverGestureRecognizer alloc]initWithTarget:self action:@selector(hoveringWithRecognizer:)];
[View addGestureRecognizer:hover];
-(void)hoveringWithRecognizer:(UIHoverGestureRecognizer *)recognizer{
switch (recognizer.state) {
case (UIGestureRecognizerStateBegan):
NSLog(@"----------------------------鼠标进入区域");
break;
case (UIGestureRecognizerStateEnded):
NSLog(@"----------------------------鼠标离开区域");
break;
default:
break;
}
}
干掉頂栏
///////也可以参考下边的方法
https://fleetingpixels.com/blog/2019/6/7/customising-nstoolbar-in-uikit-for-mac-marzipancatalyst
项目不包含 SceneDelegate.h/SceneDelegate.m的 (老项目不带这俩文件)
appDelegate.m 中
#import <Foundation/Foundation.h>
#import <UIKit/NSToolbar+UIKitAdditions.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window.windowScene.titlebar.titleVisibility = UITitlebarTitleVisibilityHidden;//隐藏顶栏
}
项目中包含 SceneDelegate.h/SceneDelegate.m 的(xcode11创建默认创建的)
在SceneDelegate.m
#import <Foundation/Foundation.h>
#import <UIKit/NSToolbar+UIKitAdditions.h>
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
UIWindowScene * windowScene = scene;
windowScene.titlebar.titleVisibility = UITitlebarTitleVisibilityHidden;
}
demo:
https://github.com/davidcaddy/UIKitForMacTestTabBarApp
----效果
顶栏添加工具栏(NSToolbar)
在appdelegate的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中添加代码
//macOS隐藏顶栏
self.window.windowScene.titlebar.titleVisibility = UITitlebarTitleVisibilityHidden;
NSToolbar * toolbar = [[NSToolbar alloc]initWithIdentifier:@"ITTitleToolbar"];
toolbar.delegate = self;
toolbar.centeredItemIdentifier = @"居中的ItemIdentifier";//例如ITtabbar
self.window.windowScene.titlebar.toolbar = toolbar;
appdelegate遵循下协议 : NSToolbarDelegate
在.m中实现协议
#pragma mark - NSToolbarDelegate
//所有的item 标识
-(NSArray<NSToolbarItemIdentifier> *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar{
return @[@"addButton",@"ITtabbar",NSToolbarFlexibleSpaceItemIdentifier,@"searchBar"];
}
-(NSArray<NSToolbarItemIdentifier> *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar{
return @[@"addButton",@"ITtabbar",NSToolbarFlexibleSpaceItemIdentifier,@"searchBar"];
}
//选中变灰
//-(NSArray<NSToolbarItemIdentifier> *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar{
// return @[@"addButton",@"ITtabbar",@"searchBar"];
//}
//根据item 标识 返回每个具体的NSToolbarItem对象实例
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
if ([itemIdentifier isEqualToString:@"ITtabbar"]) {
//这里要用NSToolbarItemGroup,子项不会分开,居中设置也可以是它(ITtabbar)
NSToolbarItemGroup * group = [NSToolbarItemGroup groupWithItemIdentifier:@"ITtabbar" titles:@[@"资讯",@"辣品",@"圈子",@"我"] selectionMode:NSToolbarItemGroupSelectionModeSelectOne labels:@[@"section1", @"section2",@"section3", @"section4"] target:self action:@selector(toolbarItemClicked:)];
[group setSelectedIndex:0];
return group;
}
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
if ([itemIdentifier isEqualToString:@"addButton"]) {
[toolbarItem setToolTip:@"更多"];
[toolbarItem setImage:[UIImage imageNamed:@"SmallAttentionButton"]];
[toolbarItem setTarget:self];
[toolbarItem setAction:@selector(addToolbarItemClicked:)];
toolbarItem.bordered = YES;
}
else if ([itemIdentifier isEqualToString:@"searchBar"]) {
[toolbarItem setToolTip:@"搜索"];
[toolbarItem setImage:[UIImage imageNamed:@"short_search"]];
[toolbarItem setTarget:self];
[toolbarItem setAction:@selector(searchToolbarItemClicked:)];
toolbarItem.bordered = YES;
}
else {
toolbarItem = nil;
}
return toolbarItem;
}
- (void)toolbarItemClicked:(NSToolbarItemGroup *)toolbarItemGroup{
switch (toolbarItemGroup.selectedIndex) {
case 0:
NSLog(@"点击的是资讯");
break;
case 1:
NSLog(@"点击的是辣品");
break;
case 2:
NSLog(@"点击的是圈子");
break;
case 3:
NSLog(@"点击的是我");
break;
default:
break;
}
}
- (void)searchToolbarItemClicked:(NSToolbarItem *)toolbarItem{
NSLog(@"点击的是%@",toolbarItem.toolTip);
}
- (void)addToolbarItemClicked:(NSToolbarItem *)toolbarItem{
NSLog(@"点击的是%@",toolbarItem.toolTip);
}
NSToolbarFlexibleSpaceItemIdentifier的解释
用这个可以达到居右对齐效果
示例代码现在是左中右布局,要在中间的item之后加入这个,不然右边的item会紧挨着中间的这个item
参考!!!!!可解决一些问题,获得启发
https://www.highcaffeinecontent.com/blog/20190607-Beyond-the-Checkbox-with-Catalyst-and-AppKit
打包问题:
1、archive 删掉Siri 功能(有的话)
2、苹果后台证书、appid、描述文件都不用动,签名选择自动(对外发布需要公证)
macOS应用Notarization公证机制
关于上架
在iOS提交界面选择macOS版本,按之前iOS的提交步骤提交即可
上一张运行图