Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Macらしいアプリケーションを実現するために / To Make Mac-like App

Avatar for tsawada2 tsawada2
December 22, 2018

Macらしいアプリケーションを実現するために / To Make Mac-like App

流行りのダークモードから、古参のサービスメニューやAppleScript、大分馴染んできた通知センターや共有ボタン…こういったmacOSの各種機能に積極的に対応することが、アプリの「Macらしさ」に繋がります。5ちゃんねるブラウザ「BathyScaphe」での実装例をご紹介します。macOS native #02 (https://macos-native.github.io) での発表資料です。

Avatar for tsawada2

tsawada2

December 22, 2018
Tweet

Other Decks in Technology

Transcript

  1. © 2018 tsawada2 macOS native #BUIZ4DBQIF w ೥͔Β։ൃ w ݩʑผͷϒϥ΢β͔Β೿ੜ

    w ݱࡏɺNBD04ઐ༻ͷϒϥ΢βͱͯ͠͸͓ͦΒ͘། Ұͷݱ໾બख !6
  2. © 2018 tsawada2 macOS native ̑ͪΌΜͶΔϒϥ΢βͱ͸ w ಈػɿ8FCϒϥ΢βΑΓ΋ޮ཰తʹɺڧྗʹӾཡ ͍ͨ͠ʢ༷ʑͳศརػೳɺϩάͷ஝ੵFUDʣ w

    ͔ͭͯ͸֤ϓϥοτϑΥʔϜ্ʹ༷ʑͳઐ༻ϒϥ΢ β͕ଘࡏ w ݱࡏ͸ॾࣄ৘ʹΑΓɺ͔ͳΓݮগ !8
  3. © 2018 tsawada2 macOS native NBD04ͷ৽ػೳΛऔΓೖΕΔϝϦοτ w ։ൃऀɿ࡞ָ͍͍ͬͯͯ͠ɺϫΫϫΫ͢Δ w Ϣʔβɿ৽͍͠04ʹͯ͠Α͔ͬͨͱ࣮ײͰ͖Δ

    w Ϣʔβɿ৽͍͠04ʹΞοϓσʔτͨ͘͠ͳΔ w ৽͍͠04ͷγΣΞ͕֦େ͢Δ w ։ൃऀɿݹ͍04Λಈ࡞ର৅͔Β֎ͤΔ w ։ൃऀɿ։ൃָ͕ʹͳΔɺָ͘͠ͳΔ !13
  4. © 2018 tsawada2 macOS native ࠓճऔΓ্͛ΔNBD04ͷػೳ !14 macOS 10.14 10.8

    OS X Mac OS X 10.0 ׽ࣈTalk 7 (7.1.1) (AppleScript) αʔϏε ௨஌ηϯλʔ ڞ༗ϝχϡʔ μʔΫϞʔυ
  5. © 2018 tsawada2 macOS native ࣄྫ ݪҼͱରॲ๏ w ৭ΛʮനʯͰృ͍ͬͯΔ͔Βʂ ˣ

    w ৭ࢦఆͷݟ௚͠ʢγεςϜΧϥʔ΁ʣ w ·ͨ͸ɺݱࡏͷ֎؍ϞʔυΛݟͯృΔ৭Λ੾Γସ͑ !23
  6. © 2018 tsawada2 macOS native ࣄྫରॲ !25 // 手っ取り早く背景を白にする self.baseView.wantsLayer

    = YES; CGColorRef white = CGColorCreateGenericGray(1.0f, 1.0f); CGColorRef white = [[NSColor controlBackgroundColor] CGColor]; self.baseView.layer.backgroundColor = white; CGColorRelease(white); എܠ৭ΛʮനʯͰ͸ͳ͘ɺద੾ͳγεςϜΧϥʔͰඳը͢Δ
  7. © 2018 tsawada2 macOS native ࡞੒ͨ͠$PMPS4FUΛݺͼग़͢ !32 - (NSColor *)infoBackgroundColor

    { if (@available(macOS 10.13, *)) { return [NSColor colorNamed:@"ThreadTitleBarInfoBg"]; } else { return [NSColor colorWithCalibratedHue:(48/360.0f) saturation:0.19f brightness:1.0f alpha:1.0f]; } }
  8. © 2018 tsawada2 macOS native εΫϩʔϥʔͷ໌Δ͞ NSScroller class reference Developer

    Documentation !35 typedef NS_ENUM(NSInteger, NSScrollerKnobStyle) { NSScrollerKnobStyleDefault = 0, // dark with light border; good against any background NSScrollerKnobStyleDark = 1, // dark; good against a light background NSScrollerKnobStyleLight = 2 // light; good against a dark background } NS_ENUM_AVAILABLE_MAC(10_7); Default Dark Light
  9. © 2018 tsawada2 macOS native ࣄྫ࠷ద੾Γସ͕͑ٲʹ w μʔΫϞʔυͰ͸ɺNSScrollerKnobStyleDefault ৭͕നͬΆ͘ͳΔˠݟͮΒ͘ͳͬͯ͠·ͬͨ !37

    Default͕നͬΆ͘ͳΔ Light͸͋·ΓมԽͳ͠ എܠ৭͸Ϣʔβ͕ࢦఆ ͢Δʹ04ͷ֎؍Ϟʔυ ͱ͸ඇಉظʂ
  10. © 2018 tsawada2 macOS native ࣄྫରॲ w ֎؍ϞʔυʹΑͬͯɺॲཧΛ੾Γସ͑ !38 CGFloat

    brightness = backgroundColor.brightnessComponent; if (ダークモードなら) { return (brightness < 0.5) ? NSScrollerKnobStyleDefault : NSScrollerKnobStyleDark; } else { // ライトモードなら return (brightness < 0.5) ? NSScrollerKnobStyleLight : NSScrollerKnobStyleDefault; }
  11. © 2018 tsawada2 macOS native ݱࡏͷ֎؍ϞʔυΛ൑ผ͢Δίʔυ !39 NSAppearance *appearance =

    someView.effectiveAppearance; // or, someWindow… if (@available(macOS 10.14, *)) { NSAppearanceName bestMatchAppearanceName = [appearance bestMatchFromAppearancesWithNames: @[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; if ([bestMatchAppearanceName isEqualToString:NSAppearanceNameDarkAqua]) { // ダークモード } else { // ライトモード } } else { // 10.13以前。常にライトモード }
  12. © 2018 tsawada2 macOS native μʔΫϞʔυ·ͱΊ w ීஈ͔Βඪ४ͷ෦඼ɺγεςϜͷΧϥʔΛ࢖͍ͬͯ Ε͹͸ͦͷ··͍͚Δ w

    ͨͩ͠ɺࡉ͔͍ͱ͜ΖͰ΍͸ΓͲ͏ͯ͠΋ߟྀ࿙Ε ͯ͠ΔՄೳੑ͸͋ΔͱݟΔ΂͖ w ௚͢͜ͱ͸ͦΕ΄ͲखؒͰ͸ͳ͍ɻݟ͚ͭ࣍ୈɺ௚ ͠·͠ΐ͏ !41
  13. © 2018 tsawada2 macOS native ରࡦίʔυ NSUserNotificationCenterDelegate Protocol Developer Documentation

    !45 // どこかでデリゲートを設定しておく [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate: (CMRAppDelegate *)[NSApp delegate]]; @implementation CMRAppDelegate(NSUserNotificationCenterDelegateImpl) // このデリゲートメソッドで常にYESを返すようにする - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { return YES; } @end
  14. © 2018 tsawada2 macOS native ௨஌ͰԻΛ໐Β͢ʹ͸ʁ NSUserNotification class reference Developer

    Documentation !46 NSUserNotification *userNotification = [[NSUserNotification alloc] init]; userNotification.title = @“Hogeeeeee!!!”; userNotification.informativeText = @“User Notification Test”; userNotification.hasActionButton = NO; userNotification.soundName = NSUserNotificationDefaultSoundName; ʻϙϩϦϯ
  15. © 2018 tsawada2 macOS native ڞ༗Ϙλϯ w Ϙλϯܕͷπʔϧόʔ߲໨Λ ༻ҙ͢Δ w

    Ϛ΢εϘλϯΛԡ͢ͱɺϝ χϡʔ͕දࣔ͞ΕΔΑ͏ʹ࣮ ૷͢Δ ˠʮ཭͢ͱʯͰ͸͋Γ·ͤΜ πʔϧόʔΞΠίϯͱͦͷ࣮૷ macOS native #01 !49 /44IBSF5FNQMBUF
  16. © 2018 tsawada2 macOS native ڞ༗Ϙλϯ w ίϯιʔϧʹܯࠂ͕ग़Δ΄Ͳେ੾ͳ͜ͱ w ίϯιʔϧʹઃఆํ๏·Ͱॻ͔Ε͍ͯΔ

    Warning: -[NSSharingServicePicker showRelativeToRect: ofView: preferredEdge:] should not be called on mouseUp Please configure the sender with -[NSControl sendActionOn:NSLeftMouseDownMask]; !50 ʮ཭͢ͱʯͰ͸͋Γ·ͤΜ
  17. © 2018 tsawada2 macOS native ڞ༗ϘλϯͷηοτΞοϓ w ݴΘΕͨ௨Γʹ࣮૷͠·͠ΐ͏ ˠͨͩ͠ίʔυهड़͕ඞཁʢ*#͔Βग़དྷͳ͍ʁʣ !51

    @property (nonatomic) IBOutlet NSButton *shareToolbarButtonItem; // どこかで最初にやっておく!(例えば -awakeFromNib とかでも…) [shareToolbarButtonItem sendActionOn:NSLeftMouseDownMask];
  18. © 2018 tsawada2 macOS native ڞ༗ϘλϯͷηοτΞοϓ !52 // 共有ボタンに以下のようなIBActionをセット -

    (IBAction)share:(id)sender { if (![sender respondsToSelector:@selector(bounds)]) { return; // 「テキストのみ」ツールバー対策(手抜き) } NSArray *items = …; // 共有したいデータを用意 NSSharingServicePicker *picker; picker = [[NSSharingServicePicker alloc] initWithItems:items]; picker.delegate = …; [picker showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; }
  19. © 2018 tsawada2 macOS native ΞχϝʔγϣϯޮՌͷ࣮૷ྫ NSSharingServiceDelegate Protocol Developer Documentation

    !54 - (NSRect) sharingService:(id)sharingService sourceFrameOnScreenForShareItem:(id<NSPasteboardWriting>)item { NSRect imageViewBounds = self.imageView.bounds; return [self.window convertRectToScreen:imageViewBounds]; } - (NSImage *)sharingService:(id)sharingService transitionImageForShareItem:(id<NSPasteboardWriting>)item contentRect:(NSRect *)contentRect { return self.imageView.image; } - (NSWindow *)sharingService:(NSSharingService *)sharingService sourceWindowForShareItems:(NSArray *)items sharingContentScope:(NSSharingContentScope *)sharingContentScope { *sharingContentScope = NSSharingContentScopeFull; return self.window; }
  20. © 2018 tsawada2 macOS native αʔϏε w .BD049ʢͱ͍͏͔ɺ/FYU45&1ͷࠒʣ͔Β͋Δ w ஍ຯͳͷʹແ͘ͳΒͳ͍

    w ίϯςΩετϝχϡʔ͔Β΋࢖͑ͨΓɺ݁ߏศར w ͜͏͍͏஍ຯ͚ͩͲૉఢͳػೳͬͯɺਪͨ͘͠ͳΓ·͢ Services Implementation Guide Documentation Archive !57 Services Human Interface Guidelines
  21. © 2018 tsawada2 macOS native "QQMF4DSJQU w ͪ͜Β͸ͳΜͱɺप೥Λܴ͑ͨػೳ w ͜Ε·ͨɺ஍ຯͳͷʹແ͘ͳΒͳ͍

    w ͣͬͱੲ͔Β৮Ε߹͖ͬͯͨػೳ͔ͩΒɺਪͨ͘͠ ͳΓ·͢ʂ w ਪ͠ΛߦಈͰࣔ͢ʹࣗ࡞ΞϓϦͰରԠ͢Δʂ !61
  22. © 2018 tsawada2 macOS native ΞϓϦέʔγϣϯͷ"QQMF4DSJQUରԠϨϕϧ w 4DSJQUBCMF w "UUBDIBCMF

    w 3FDPSEBCMF !62 ׽ࣈ5BMLͷࠒɺΑ͘ҎԼͷͭͷ୯ޠͰઆ໌͞Ε͍ͯͨ ͜Ε͸νϣοτେม͔΋
  23. © 2018 tsawada2 macOS native 4DSJQUBCMF"QQMJDBUJPOʹͳΔʹ͸ w ༻ޠࣙॻΛॻ͘ɺ͜Εʹਚ͖Δ w ग़དྷΔ͚ͩ։ൃͷॳظஈ֊͔Βߟྀ͓ͯ͘͠

    w ͓͢͢ΊɿӅ͠ઃఆ΁ͷΞΫηεखஈͱͯ͠׆༻ AppleScript Λαϙʔτ͢Δ macOS native #03 ʹظ଴ !63
  24. © 2018 tsawada2 macOS native "UUBDIBCMF"QQMJDBUJPOʹͳΔʹ͸ w εΫϦϓτͷ࣮ߦ͸ɺઐ༻Ϋϥε͕͋ΔͷͰ؆୯ w ͓͢͢ΊɿεΫϦϓτϝχϡʔΛ͚ͭͯΈ·ͤΜ͔

    w 4DSJQUBCMFͳͱ͖ɺ"UUBDIBCMF͕׆͖ͯ͘Δ NSUserAppleScriptTask class reference Developer Documentation !64
  25. © 2018 tsawada2 macOS native ͍ͭͰ΋޷͖ͳ࣌ʹʮ͋ͷԻʯΛ໐Βͦ͏ System Sound Services Developer

    Documentation !68 @import AudioToolbox; AudioServicesPlaySystemSound(22); // Disc Burned AudioServicesPlaySystemSound(16); // Trash! AudioServicesPlaySystemSound(1); // Move etc. AudioServicesPlaySystemSound(15); // Boom!