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

iOSの隠されたAPIを解明し、開発効率を向上させる方法/iOSDC24

 iOSの隠されたAPIを解明し、開発効率を向上させる方法/iOSDC24

noppefoxwolf

August 24, 2024
Tweet

More Decks by noppefoxwolf

Other Decks in Programming

Transcript

  1. How to access hidden iOS APIs and enhance development efficacy.

    2024/08/23 10:50ʙ Track B Regular talkʢ20 minʣ 1/53
  2. DeNA Co., Ltd., • 2016 ~ • Pococha • iOS

    Senior App Developer • Code de Crossword at DeNA booth • They are sponsoring my talk 3/53
  3. Enjoy my talk! • The talk will be in Japanese

    • Slides are in English 4/53
  4. ObjC Private API Sample *object = [Sample new]; // Success

    [object send]; // Error [object validate]; 10/53
  5. ObjC Private API You can expose the method by adding

    a header file yourself. @interface Sample (Private) - (BOOL)validate; @end // Success [objcect validate]; 11/53
  6. ObjC Private API You can call the method by using

    performSelector without adding a header file. [object performSelector:NSSelectorFromString(@"validate")]; 12/53
  7. Swift Hidden API • Swift does not have any header

    file. • Dynamic Link Framework has Swift module data. 14/53
  8. Swift Hidden API • tbd file • dynamic library stub

    for Eager linking 4 • public and internal api list • swiftinterface file • public api list 4 https://developer.apple.com/jp/videos/play/wwdc2022/110364/ 15/53
  9. Swift Hidden API /Applications /Xcode.app /Contents /Developer /Platforms /iPhoneSimulator.platform /Developer

    /SDKs /iPhoneSimulator.sdk /System /Library /Frameworks /SwiftUI.framework 16/53
  10. Swift Hidden API SwiftUI.framework ├── Headers │ ├── SwiftUI.h │

    └── SwiftUI_Metal.h ├── Modules │ ├── SwiftUI.swiftmodule │ │ ├── arm64-apple-ios-simulator.swiftdoc │ │ ├── arm64-apple-ios-simulator.swiftinterface │ │ ├── x86_64-apple-ios-simulator.swiftdoc │ │ └── x86_64-apple-ios-simulator.swiftinterface │ └── module.modulemap └── SwiftUI.tbd 17/53
  11. Swift Hidden API arm64-apple-ios-simulator.swiftinterface ... @_Concurrency.MainActor open class UIHostingController<Content> :

    UIKit.UIViewController where Content : SwiftUICore.View { @_Concurrency.MainActor @preconcurrency public var _disableSafeArea: Swift.Bool { get set } } ... 18/53
  12. Swift Hidden API SwiftUI.tbd --- !tapi-tbd tbd-version: 0 targets: [

    i386-ios-simulator, x86_64-ios-simulator, arm64-ios-simulator ] install-name: '/System/Library/Frameworks/SwiftUI.framework/SwiftUI' current-version: 0.0.0 swift-abi-version: 0 exports: - targets: [ i386-ios-simulator, x86_64-ios-simulator, arm64-ios-simulator ] symbols: [ ... ] 20/53
  13. Swift Hidden API modify swiftinterface file yourself @available(iOS 17.0, macOS

    14.0, watchOS 10.0, tvOS 17.0, *) extension SwiftUICore.View { nonisolated public func variableBlur( maxRadius: CoreFoundation.CGFloat, mask: SwiftUI.Image, opaque: Swift.Bool ) -> some SwiftUI.View } 23/53
  14. UnderscoredAttributes1 5 extension View { @_disfavoredOverload func badge(_ count: Int)

    -> some View { // ... } } 5 https://github.com/swiftlang/swift/pull/37854 1 https://github.com/swiftlang/swift/blob/main/docs/ReferenceGuides/UnderscoredAttributes.md 25/53
  15. Hidden API's risk ⚠ • Semantics are subject to change.

    • Side-effects are not controllable. • AppStore rejection • Uncompliance in review guildeline 2.5.12 2 https://developer.apple.com/jp/app-store/review/guidelines/ 27/53
  16. Lowering risk • Testing for lowing changing and side-effects risk.

    func testPrivateMethod() { let object = Sample() let selector = #Selector("setUserName:") object.performSelector(selector, withObject: "noppe") #expect(object.userName == "noppe") if !object.responds(selector) { fatalError("Selector not found") } } 28/53
  17. Concept Development • Concept Development, Hackathon, UI Design, and more.

    • Troublesome implementation • Difficult implementation • Complex visual effect 31/53
  18. UITextView.setAttributedPlaceholder:8 extension UITextView { func setPlaceholder(_ placeholder: String?) { let

    string = placeholder.map(NSAttributedString.init) let selector = Selector(("setAttributedPlaceholder:")) if responds(to: selector) { perform(selector, with: string) } } } 8 https://gist.github.com/AdamWhitcroft/c6ffc0323b9ce227588df7145685ae26#file-wrappeduitextview-swift-L41 32/53
  19. UINavigationItem._setWeeTitle:7 extension UINavigationItem { func setWeeTitle(_ title: String) { let

    selector = Selector(("_setWeeTitle:")) if responds(to: selector) { perform(selector, with: title as NSString) } } } 7 https://github.com/feedback-assistant/reports/issues/506 34/53
  20. Testing UIDebuggingInformationOverla y • iOS10 • easy to use •

    iOS11+ • needs to jump through some hoops 38/53
  21. Product Development Using hidden API is risky. But, You can

    learn API design from hidden APIs. 40/53
  22. API naming You can learn API naming rules from official

    SDK headers. -(void)_endScrollingCursorOverrideIfNecessary; -(UIOffset)_firstPageOffset; -(id)_frameLayoutGuideIfExists; (note) Don't override the method names, because ObjC uses Dynamic Dispatch. 41/53
  23. API design You can learn UI scructures and architectures. @interface

    UITextView : UIScrollView { _UITextContainerView* _containerView; ... } ... @end 42/53
  24. How to find hidden APIs? • Read swiftinterface, tbd and

    headers. • Get method name list • Read the stacktrace • Find SNS posts • Send feedback to Apple 43/53
  25. Get method name list _methodDescription (located in UIKitCore) import UIKit

    let selector = Selector("_methodDescription") let names = scrollView.perform(selector) print(names) 44/53
  26. Get method name list • Runtime Header • p-x9/swift-objc-dump9 9

    https://github.com/p-x9/swift-objc-dump 45/53
  27. Send feedback to Apple • Apple sometimes publicizes the API

    after receiving our feedback. • Write feedback about usecases and APIs. 49/53