{"id":"5ff8341d-18f2-4df1-b2f8-a093609c0350","shortId":"wGHJy6","kind":"skill","title":"avkit","tagline":"Create media playback experiences using AVKit. Use when adding video players with AVPlayerViewController, enabling Picture-in-Picture, routing media with AirPlay, using SwiftUI VideoPlayer views, configuring transport controls, displaying subtitles and closed captions, or integra","description":"# AVKit\n\nHigh-level media playback UI built on AVFoundation. Provides system-standard\nvideo players, Picture-in-Picture, AirPlay routing, transport controls, and\nsubtitle/caption display. Targets Swift 6.3 / iOS 26+.\n\n## Contents\n\n- [Setup](#setup)\n- [AVPlayerViewController](#avplayerviewcontroller)\n- [SwiftUI VideoPlayer](#swiftui-videoplayer)\n- [Picture-in-Picture](#picture-in-picture)\n- [AirPlay](#airplay)\n- [Transport Controls and Playback Speed](#transport-controls-and-playback-speed)\n- [Subtitles and Closed Captions](#subtitles-and-closed-captions)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Setup\n\n### Audio Session Configuration\n\nConfigure the audio session and background modes before any playback. Without\nthis, PiP and background audio fail silently.\n\n1. Add the `audio` background mode to `UIBackgroundModes` in Info.plist\n2. Set the audio session category to `.playback`\n\n```swift\nimport AVFoundation\n\nfunc configureAudioSession() {\n    let session = AVAudioSession.sharedInstance()\n    do {\n        try session.setCategory(.playback, mode: .moviePlayback)\n        try session.setActive(true)\n    } catch {\n        print(\"Audio session configuration failed: \\(error)\")\n    }\n}\n```\n\n### Imports\n\n```swift\nimport AVKit          // AVPlayerViewController, VideoPlayer, PiP\nimport AVFoundation   // AVPlayer, AVPlayerItem, AVAsset\n```\n\n## AVPlayerViewController\n\n`AVPlayerViewController` is the standard UIKit player. It provides system\nplayback controls, PiP, AirPlay, subtitles, and frame analysis out of the box.\nDo not subclass it.\n\n### Basic Presentation (Full Screen)\n\n```swift\nimport AVKit\n\nfunc presentPlayer(from viewController: UIViewController, url: URL) {\n    let player = AVPlayer(url: url)\n    let playerVC = AVPlayerViewController()\n    playerVC.player = player\n\n    viewController.present(playerVC, animated: true) {\n        player.play()\n    }\n}\n```\n\n### Inline (Embedded) Playback\n\nAdd `AVPlayerViewController` as a child view controller for inline playback.\nCall `addChild`, add the view with constraints, then call `didMove(toParent:)`.\n\n```swift\nfunc embedPlayer(in parent: UIViewController, container: UIView, url: URL) {\n    let playerVC = AVPlayerViewController()\n    playerVC.player = AVPlayer(url: url)\n\n    parent.addChild(playerVC)\n    container.addSubview(playerVC.view)\n    playerVC.view.translatesAutoresizingMaskIntoConstraints = false\n    NSLayoutConstraint.activate([\n        playerVC.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),\n        playerVC.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),\n        playerVC.view.topAnchor.constraint(equalTo: container.topAnchor),\n        playerVC.view.bottomAnchor.constraint(equalTo: container.bottomAnchor)\n    ])\n    playerVC.didMove(toParent: parent)\n}\n```\n\n### Key Properties\n\n```swift\nplayerVC.showsPlaybackControls = true                    // Show/hide system controls\nplayerVC.videoGravity = .resizeAspect                    // .resizeAspectFill to crop\nplayerVC.entersFullScreenWhenPlaybackBegins = false\nplayerVC.exitsFullScreenWhenPlaybackEnds = true\nplayerVC.updatesNowPlayingInfoCenter = true              // Auto-updates MPNowPlayingInfoCenter\n```\n\nUse `contentOverlayView` to add non-interactive views (watermarks, logos)\nbetween the video and transport controls.\n\n### Delegate\n\nAdopt `AVPlayerViewControllerDelegate` to respond to full-screen transitions,\nPiP lifecycle events, interstitial playback, and media selection changes.\nUse the transition coordinator's `animate(alongsideTransition:completion:)` to\nsynchronize your UI with full-screen animations.\n\n### Display Readiness\n\nObserve `isReadyForDisplay` before showing the player to avoid a black flash:\n\n```swift\nlet observation = playerVC.observe(\\.isReadyForDisplay) { observed, _ in\n    if observed.isReadyForDisplay {\n        // Safe to show the player view\n    }\n}\n```\n\n## SwiftUI VideoPlayer\n\nThe `VideoPlayer` SwiftUI view wraps AVKit's playback UI.\n\n### Basic Usage\n\n```swift\nimport SwiftUI\nimport AVKit\n\nstruct PlayerView: View {\n    @State private var player: AVPlayer?\n\n    var body: some View {\n        Group {\n            if let player {\n                VideoPlayer(player: player)\n                    .frame(height: 300)\n            } else {\n                ProgressView()\n            }\n        }\n        .task {\n            let url = URL(string: \"https://example.com/video.m3u8\")!\n            player = AVPlayer(url: url)\n        }\n    }\n}\n```\n\n### Video Overlay\n\nAdd a non-interactive SwiftUI overlay on top of video content.\n\n```swift\nVideoPlayer(player: player) {\n    VStack {\n        Spacer()\n        HStack {\n            Image(\"logo\")\n                .resizable()\n                .frame(width: 40, height: 40)\n                .padding()\n            Spacer()\n        }\n    }\n}\n```\n\n### UIKit Hosting for Advanced Control\n\n`VideoPlayer` does not expose all `AVPlayerViewController` properties. For PiP\nconfiguration, delegate callbacks, or playback speed control, wrap\n`AVPlayerViewController` in a `UIViewControllerRepresentable`. See the full\npattern in [references/avkit-patterns.md](references/avkit-patterns.md).\n\n## Picture-in-Picture\n\nPiP lets users watch video in a floating window while using other apps.\n`AVPlayerViewController` supports PiP automatically once the audio session is\nconfigured. For custom player UIs, use `AVPictureInPictureController` directly.\n\n### Prerequisites\n\n1. Audio session category set to `.playback` (see [Setup](#setup))\n2. `audio` background mode in `UIBackgroundModes`\n\n### Standard Player PiP\n\nPiP is enabled by default on `AVPlayerViewController`. Control automatic\nactivation and inline-to-PiP transitions:\n\n```swift\nlet playerVC = AVPlayerViewController()\nplayerVC.player = player\n\n// PiP enabled by default; set false to disable\nplayerVC.allowsPictureInPicturePlayback = true\n\n// Auto-start PiP when app backgrounds (for inline/non-fullscreen players)\nplayerVC.canStartPictureInPictureAutomaticallyFromInline = true\n```\n\n### Restoring the UI When PiP Stops\n\nWhen the user taps the restore button in PiP, implement the delegate method to\nre-present your player. Call the completion handler with `true` to signal the\nsystem to finish the restore animation.\n\n```swift\nfunc playerViewController(\n    _ playerViewController: AVPlayerViewController,\n    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void\n) {\n    // Re-present or re-embed the player view controller\n    present(playerViewController, animated: false) {\n        completionHandler(true)\n    }\n}\n```\n\n### Custom Player PiP\n\nFor custom player UIs, use `AVPictureInPictureController` with an `AVPlayerLayer`\nor sample buffer content source. Check `isPictureInPictureSupported()` first.\nSee [references/avkit-patterns.md](references/avkit-patterns.md) for full custom player and sample buffer\nPiP patterns.\n\n```swift\nguard AVPictureInPictureController.isPictureInPictureSupported() else { return }\nlet pipController = AVPictureInPictureController(playerLayer: playerLayer)\npipController.delegate = self\npipController.canStartPictureInPictureAutomaticallyFromInline = true\n```\n\n### Linear Playback During Ads\n\nPrevent seeking during ads or legal notices by toggling `requiresLinearPlayback`:\n\n```swift\n// During an ad\nplayerVC.requiresLinearPlayback = true\n\n// After the ad completes\nplayerVC.requiresLinearPlayback = false\n```\n\n## AirPlay\n\n`AVPlayerViewController` supports AirPlay automatically. No additional code is\nrequired when using the standard player. The system displays the AirPlay button\nin the transport controls when AirPlay-capable devices are available.\n\n### AVRoutePickerView\n\nAdd a standalone AirPlay route picker button outside the player UI:\n\n```swift\nimport AVKit\n\nfunc addRoutePicker(to containerView: UIView) {\n    let routePicker = AVRoutePickerView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))\n    routePicker.activeTintColor = .systemBlue\n    routePicker.prioritizesVideoDevices = true  // Show video-capable routes first\n    containerView.addSubview(routePicker)\n}\n```\n\n### Enabling External Playback\n\nEnsure `AVPlayer` allows external playback (enabled by default):\n\n```swift\nplayer.allowsExternalPlayback = true\nplayer.usesExternalPlaybackWhileExternalScreenIsActive = true\n```\n\n## Transport Controls and Playback Speed\n\n### Custom Playback Speeds\n\nProvide user-selectable playback speeds in the player UI:\n\n```swift\nlet playerVC = AVPlayerViewController()\nplayerVC.speeds = [\n    AVPlaybackSpeed(rate: 0.5, localizedName: \"Half Speed\"),\n    AVPlaybackSpeed(rate: 1.0, localizedName: \"Normal\"),\n    AVPlaybackSpeed(rate: 1.5, localizedName: \"1.5x\"),\n    AVPlaybackSpeed(rate: 2.0, localizedName: \"Double Speed\")\n]\n```\n\nUse `AVPlaybackSpeed.systemDefaultSpeeds` to restore the default speed options.\n\n### Skipping Behavior\n\nConfigure forward/backward skip controls:\n\n```swift\nplayerVC.isSkipForwardEnabled = true\nplayerVC.isSkipBackwardEnabled = true\n```\n\n### Now Playing Integration\n\n`AVPlayerViewController` updates `MPNowPlayingInfoCenter` automatically by\ndefault. Disable this if you manage Now Playing info manually:\n\n```swift\nplayerVC.updatesNowPlayingInfoCenter = false\n```\n\n## Subtitles and Closed Captions\n\nAVKit handles subtitle and closed caption display automatically when the media\ncontains appropriate text tracks. Users control subtitle preferences in\nSettings > Accessibility > Subtitles & Captioning.\n\n### Restricting Subtitle Languages\n\n```swift\n// Only show English and Spanish subtitle options\nplayerVC.allowedSubtitleOptionLanguages = [\"en\", \"es\"]\n```\n\n### Requiring Subtitles\n\nForce subtitles to always display (the user cannot turn them off):\n\n```swift\nplayerVC.requiresFullSubtitles = true\n```\n\n### Media Selection (Delegate)\n\nRespond to the user changing subtitle or audio track selection:\n\n```swift\nfunc playerViewController(\n    _ playerViewController: AVPlayerViewController,\n    didSelect mediaSelectionOption: AVMediaSelectionOption?,\n    in mediaSelectionGroup: AVMediaSelectionGroup\n) {\n    if let option = mediaSelectionOption {\n        print(\"Selected: \\(option.displayName)\")\n    }\n}\n```\n\n### Providing Subtitle Tracks in HLS\n\nSubtitles and closed captions are embedded in HLS manifests. AVKit reads them\nfrom `AVMediaSelectionGroup` on the `AVAsset`. For local files, use\n`AVMutableComposition` to add `AVMediaCharacteristic.legible` tracks.\n\n## Common Mistakes\n\n### DON'T: Subclass AVPlayerViewController\n\nApple explicitly states this is unsupported. It may cause undefined behavior or\ncrash on future OS versions.\n\n```swift\n// WRONG\nclass MyPlayerVC: AVPlayerViewController { } // Unsupported\n\n// CORRECT: Use composition with delegation\nlet playerVC = AVPlayerViewController()\nplayerVC.delegate = coordinator\n```\n\n### DON'T: Skip audio session configuration for PiP\n\nPiP fails silently if the audio session is not set to `.playback`. Background\naudio also stops working.\n\n```swift\n// WRONG: Default audio session\nlet playerVC = AVPlayerViewController()\nplayerVC.player = player // PiP won't work\n\n// CORRECT: Configure audio session first\ntry AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)\ntry AVAudioSession.sharedInstance().setActive(true)\nlet playerVC = AVPlayerViewController()\nplayerVC.player = player\n```\n\n### DON'T: Forget the PiP restore delegate or its completion handler\n\nWithout `restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`, the\nsystem cannot return the user to your player. Failing to call\n`completionHandler(true)` leaves the system in an inconsistent state.\n\n```swift\n// WRONG: No delegate method or missing completionHandler call\n// User taps restore in PiP -> nothing happens or animation hangs\n\n// CORRECT\nfunc playerViewController(\n    _ playerViewController: AVPlayerViewController,\n    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void\n) {\n    present(playerViewController, animated: false) {\n        completionHandler(true)\n    }\n}\n```\n\n### DON'T: Create AVPlayer in a SwiftUI view's init\n\nCreating the player eagerly causes performance issues. SwiftUI may recreate the\nview multiple times.\n\n```swift\n// WRONG: Created on every view init\nstruct PlayerView: View {\n    let player = AVPlayer(url: videoURL) // Re-created on every view evaluation\n\n    var body: some View { VideoPlayer(player: player) }\n}\n\n// CORRECT: Use @State and defer creation\nstruct PlayerView: View {\n    @State private var player: AVPlayer?\n\n    var body: some View {\n        VideoPlayer(player: player)\n            .task { player = AVPlayer(url: videoURL) }\n    }\n}\n```\n\n## Review Checklist\n\n- [ ] Audio session category set to `.playback` with `mode: .moviePlayback`\n- [ ] `audio` background mode added to `UIBackgroundModes` in Info.plist\n- [ ] `AVPlayerViewController` is not subclassed\n- [ ] PiP restore delegate method implemented and calls `completionHandler(true)`\n- [ ] `AVPlayer` deferred to `.task` in SwiftUI (not created eagerly)\n- [ ] `canStartPictureInPictureAutomaticallyFromInline` set for inline players\n- [ ] `requiresLinearPlayback` toggled only during required ad/legal segments\n- [ ] `allowsExternalPlayback` enabled on `AVPlayer` for AirPlay support\n- [ ] Subtitle language restrictions tested with actual media tracks\n- [ ] Video gravity set appropriately (`.resizeAspect` vs `.resizeAspectFill`)\n- [ ] `isReadyForDisplay` observed before showing the player view\n- [ ] Error handling for network-streamed content (HLS failures, timeouts)\n\n## References\n\n- Advanced patterns (custom player UI, interstitials, background playback, error handling): [references/avkit-patterns.md](references/avkit-patterns.md)\n- [AVKit framework](https://sosumi.ai/documentation/avkit)\n- [AVPlayerViewController](https://sosumi.ai/documentation/avkit/avplayerviewcontroller)\n- [VideoPlayer (SwiftUI)](https://sosumi.ai/documentation/avkit/videoplayer)\n- [AVPictureInPictureController](https://sosumi.ai/documentation/avkit/avpictureinpicturecontroller)\n- [AVRoutePickerView](https://sosumi.ai/documentation/avkit/avroutepickerview)\n- [AVPlaybackSpeed](https://sosumi.ai/documentation/avkit/avplaybackspeed)\n- [Configuring your app for media playback](https://sosumi.ai/documentation/avfoundation/configuring-your-app-for-media-playback)\n- [Adopting Picture in Picture in a Standard Player](https://sosumi.ai/documentation/avkit/adopting-picture-in-picture-in-a-standard-player)\n- [Playing video content in a standard user interface](https://sosumi.ai/documentation/avkit/playing-video-content-in-a-standard-user-interface)","tags":["avkit","swift","ios","skills","dpearson2699","accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills"],"capabilities":["skill","source-dpearson2699","skill-avkit","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/avkit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.684","qualityRationale":"deterministic score 0.68 from registry signals: · indexed on github topic:agent-skills · 468 github stars · SKILL.md body (14,644 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T00:53:41.682Z","embedding":null,"createdAt":"2026-04-18T22:00:46.341Z","updatedAt":"2026-04-22T00:53:41.682Z","lastSeenAt":"2026-04-22T00:53:41.682Z","tsv":"'/documentation/avfoundation/configuring-your-app-for-media-playback)':1458 '/documentation/avkit)':1428 '/documentation/avkit/adopting-picture-in-picture-in-a-standard-player)':1469 '/documentation/avkit/avpictureinpicturecontroller)':1441 '/documentation/avkit/avplaybackspeed)':1449 '/documentation/avkit/avplayerviewcontroller)':1432 '/documentation/avkit/avroutepickerview)':1445 '/documentation/avkit/playing-video-content-in-a-standard-user-interface)':1480 '/documentation/avkit/videoplayer)':1437 '/video.m3u8':468 '0':832,834 '0.5':892 '1':144,572 '1.0':898 '1.5':903,905 '2':154,582 '2.0':909 '26':69 '300':458 '40':499,501 '44':836,838 '6.3':67 'access':978 'activ':600 'actual':1384 'ad':10,751,755,765,770,1333 'ad/legal':1370 'add':145,256,268,342,475,807,1070 'addchild':267 'addit':780 'addroutepick':822 'adopt':356,1459 'advanc':507,1412 'airplay':23,58,88,89,211,774,777,793,801,810,1377 'airplay-cap':800 'allow':856 'allowsexternalplayback':1372 'alongsidetransit':380 'also':1134 'alway':1000 'analysi':215 'anim':250,379,390,674,698,1222,1236 'app':553,628,1452 'appl':1079 'appropri':969,1390 'audio':123,128,141,147,157,181,560,573,583,1021,1115,1125,1133,1140,1153,1321,1330 'auto':336,624 'auto-start':623 'auto-upd':335 'automat':557,599,778,938,964 'avail':805 'avasset':197,1063 'avaudiosession.sharedinstance':169,1157,1163 'avfound':47,164,194 'avkit':1,7,38,189,230,426,436,820,957,1056,1424 'avmediacharacteristic.legible':1071 'avmediaselectiongroup':1034,1060 'avmediaselectionopt':1031 'avmutablecomposit':1068 'avoid':400 'avpictureinpicturecontrol':569,710,741,1438 'avpictureinpicturecontroller.ispictureinpicturesupported':736 'avplay':195,240,291,444,470,855,1243,1276,1306,1316,1351,1375 'avplaybackspe':890,896,901,907,1446 'avplaybackspeed.systemdefaultspeeds':914 'avplayeritem':196 'avplayerlay':713 'avplayerviewcontrol':14,73,74,190,198,199,245,257,289,514,526,554,597,610,679,775,888,935,1028,1078,1100,1109,1144,1168,1228,1338,1429 'avplayerviewcontrollerdeleg':357 'avroutepickerview':806,828,1442 'background':131,140,148,584,629,1132,1331,1418 'basic':224,430 'behavior':922,1089 'black':402 'bodi':446,1287,1308 'bool':683,1232 'box':219 'buffer':716,731 'built':45 'button':647,794,813 'call':266,274,660,1195,1213,1348 'callback':520 'cannot':1004,1186 'canstartpictureinpictureautomaticallyfrominlin':1360 'capabl':802,846 'caption':35,104,109,956,962,980,1050 'catch':179 'categori':159,575,1323 'caus':1087,1254 'cgrect':830 'chang':373,1018 'check':719 'checklist':116,119,1320 'child':260 'class':1098 'close':34,103,108,955,961,1049 'code':781 'common':110,113,1073 'common-mistak':112 'complet':381,662,771,1180 'completionhandl':681,700,1196,1212,1230,1238,1349 'composit':1104 'configur':28,125,126,183,518,563,923,1117,1152,1450 'configureaudiosess':166 'constraint':272 'contain':283,968 'container.addsubview':296 'container.bottomanchor':312 'container.leadinganchor':303 'container.topanchor':309 'container.trailinganchor':306 'containerview':824 'containerview.addsubview':849 'content':70,486,717,1407,1472 'contentoverlayview':340 'control':30,61,91,97,209,262,323,354,508,524,598,695,798,868,926,973 'coordin':377,1111 'correct':1102,1151,1224,1293 'crash':1091 'creat':2,1242,1250,1266,1281,1358 'creation':1298 'crop':328 'custom':565,702,706,727,872,1414 'default':595,616,861,918,940,1139 'defer':1297,1352 'deleg':355,519,652,1013,1106,1177,1208,1344 'devic':803 'didmov':275 'didselect':1029 'direct':570 'disabl':620,941 'display':31,64,391,791,963,1001 'doubl':911 'eager':1253,1359 'els':459,737 'emb':691 'embed':254,1052 'embedplay':279 'en':993 'enabl':15,593,614,851,859,1373 'english':987 'ensur':854 'equalto':302,305,308,311 'error':185,1401,1420 'es':994 'escap':682,1231 'evalu':1285 'event':367 'everi':1268,1283 'example.com':467 'example.com/video.m3u8':466 'experi':5 'explicit':1080 'expos':512 'extern':852,857 'fail':142,184,1121,1193 'failur':1409 'fals':299,330,618,699,773,952,1237 'file':1066 'finish':671 'first':721,848,1155 'flash':403 'float':548 'forc':997 'forget':1173 'forward/backward':924 'frame':214,456,497,829 'framework':1425 'full':226,362,388,532,726 'full-screen':361,387 'func':165,231,278,676,821,1025,1225 'futur':1093 'graviti':1388 'group':449 'guard':735 'half':894 'handl':958,1402,1421 'handler':663,1181 'hang':1223 'happen':1220 'height':457,500,837 'high':40 'high-level':39 'hls':1046,1054,1408 'host':505 'hstack':493 'imag':494 'implement':650,1346 'import':163,186,188,193,229,433,435,819 'inconsist':1203 'info':948 'info.plist':153,1337 'init':1249,1270 'inlin':253,264,603,1363 'inline-to-pip':602 'inline/non-fullscreen':631 'integr':934 'integra':37 'interact':345,479 'interfac':1477 'interstiti':368,1417 'io':68 'ispictureinpicturesupport':720 'isreadyfordisplay':394,408,1394 'issu':1256 'key':316 'languag':983,1380 'leav':1198 'legal':757 'let':167,238,243,287,405,451,462,542,608,739,826,886,1036,1107,1142,1166,1274 'level':41 'lifecycl':366 'linear':748 'local':1065 'localizednam':893,899,904,910 'logo':348,495 'manag':945 'manifest':1055 'manual':949 'may':1086,1258 'media':3,21,42,371,967,1011,1385,1454 'mediaselectiongroup':1033 'mediaselectionopt':1030,1038 'method':653,1209,1345 'miss':1211 'mistak':111,114,1074 'mode':132,149,174,585,1160,1328,1332 'movieplayback':175,1161,1329 'mpnowplayinginfocent':338,937 'multipl':1262 'myplayervc':1099 'network':1405 'network-stream':1404 'non':344,478 'non-interact':343,477 'normal':900 'noth':1219 'notic':758 'nslayoutconstraint.activate':300 'observ':393,406,409,1395 'observed.isreadyfordisplay':412 'option':920,991,1037 'option.displayname':1041 'os':1094 'outsid':814 'overlay':474,481 'pad':502 'parent':281,315 'parent.addchild':294 'pattern':533,733,1413 'perform':1255 'picker':812 'pictur':17,19,55,57,81,83,85,87,538,540,1460,1462 'picture-in-pictur':16,54,80,84,537 'pip':138,192,210,365,517,541,556,590,591,605,613,626,639,649,704,732,1119,1120,1147,1175,1218,1342 'pipcontrol':740 'pipcontroller.canstartpictureinpictureautomaticallyfrominline':746 'pipcontroller.delegate':744 'play':933,947,1470 'playback':4,43,93,99,135,161,173,208,255,265,369,428,522,578,749,853,858,870,873,879,1131,1159,1326,1419,1455 'player':12,53,204,239,247,398,417,443,452,454,455,469,489,490,566,589,612,632,659,693,703,707,728,788,816,883,1146,1170,1192,1252,1275,1291,1292,1305,1312,1313,1315,1364,1399,1415,1466 'player.allowsexternalplayback':863 'player.play':252 'player.usesexternalplaybackwhileexternalscreenisactive':865 'playerlay':742,743 'playervc':244,249,288,295,609,887,1108,1143,1167 'playervc.allowedsubtitleoptionlanguages':992 'playervc.allowspictureinpictureplayback':621 'playervc.canstartpictureinpictureautomaticallyfrominline':633 'playervc.delegate':1110 'playervc.didmove':313 'playervc.entersfullscreenwhenplaybackbegins':329 'playervc.exitsfullscreenwhenplaybackends':331 'playervc.isskipbackwardenabled':930 'playervc.isskipforwardenabled':928 'playervc.observe':407 'playervc.player':246,290,611,1145,1169 'playervc.requiresfullsubtitles':1009 'playervc.requireslinearplayback':766,772 'playervc.showsplaybackcontrols':319 'playervc.speeds':889 'playervc.updatesnowplayinginfocenter':333,951 'playervc.videogravity':324 'playervc.view':297 'playervc.view.bottomanchor.constraint':310 'playervc.view.leadinganchor.constraint':301 'playervc.view.topanchor.constraint':307 'playervc.view.trailinganchor.constraint':304 'playervc.view.translatesautoresizingmaskintoconstraints':298 'playerview':438,1272,1300 'playerviewcontrol':677,678,697,1026,1027,1226,1227,1235 'prefer':975 'prerequisit':571 'present':225,657,687,696,1234 'presentplay':232 'prevent':752 'print':180,1039 'privat':441,1303 'progressview':460 'properti':317,515 'provid':48,206,875,1042 'rate':891,897,902,908 're':656,686,690,1280 're-creat':1279 're-emb':689 're-pres':655,685 'read':1057 'readi':392 'recreat':1259 'refer':120,121,1411 'references/avkit-patterns.md':535,536,723,724,1422,1423 'requir':783,995,1369 'requireslinearplayback':761,1365 'resiz':496 'resizeaspect':325,1391 'resizeaspectfil':326,1393 'respond':359,1014 'restor':635,646,673,916,1176,1216,1343 'restoreuserinterfaceforpictureinpicturestopwithcompletionhandl':680,1183,1229 'restrict':981,1381 'return':738,1187 'review':115,118,1319 'review-checklist':117 'rout':20,59,811,847 'routepick':827,850 'routepicker.activetintcolor':839 'routepicker.prioritizesvideodevices':841 'safe':413 'sampl':715,730 'screen':227,363,389 'see':530,579,722 'seek':753 'segment':1371 'select':372,878,1012,1023,1040 'self':745 'session':124,129,158,168,182,561,574,1116,1126,1141,1154,1322 'session.setactive':177 'session.setcategory':172 'set':155,576,617,977,1129,1324,1361,1389 'setact':1164 'setcategori':1158 'setup':71,72,122,580,581 'show':396,415,843,986,1397 'show/hide':321 'signal':667 'silent':143,1122 'skill' 'skill-avkit' 'skip':921,925,1114 'sosumi.ai':1427,1431,1436,1440,1444,1448,1457,1468,1479 'sosumi.ai/documentation/avfoundation/configuring-your-app-for-media-playback)':1456 'sosumi.ai/documentation/avkit)':1426 'sosumi.ai/documentation/avkit/adopting-picture-in-picture-in-a-standard-player)':1467 'sosumi.ai/documentation/avkit/avpictureinpicturecontroller)':1439 'sosumi.ai/documentation/avkit/avplaybackspeed)':1447 'sosumi.ai/documentation/avkit/avplayerviewcontroller)':1430 'sosumi.ai/documentation/avkit/avroutepickerview)':1443 'sosumi.ai/documentation/avkit/playing-video-content-in-a-standard-user-interface)':1478 'sosumi.ai/documentation/avkit/videoplayer)':1435 'sourc':718 'source-dpearson2699' 'spacer':492,503 'spanish':989 'speed':94,100,523,871,874,880,895,912,919 'standalon':809 'standard':51,202,588,787,1465,1475 'start':625 'state':440,1081,1204,1295,1302 'stop':640,1135 'stream':1406 'string':465 'struct':437,1271,1299 'subclass':222,1077,1341 'subtitl':32,101,106,212,953,959,974,979,982,990,996,998,1019,1043,1047,1379 'subtitle/caption':63 'subtitles-and-closed-capt':105 'support':555,776,1378 'swift':66,162,187,228,277,318,404,432,487,607,675,734,762,818,862,885,927,950,984,1008,1024,1096,1137,1205,1264 'swiftui':25,75,78,419,423,434,480,1246,1257,1356,1434 'swiftui-videoplay':77 'synchron':383 'system':50,207,322,669,790,1185,1200 'system-standard':49 'systemblu':840 'tap':644,1215 'target':65 'task':461,1314,1354 'test':1382 'text':970 'time':1263 'timeout':1410 'toggl':760,1366 'top':483 'topar':276,314 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'track':971,1022,1044,1072,1386 'transit':364,376,606 'transport':29,60,90,96,353,797,867 'transport-controls-and-playback-spe':95 'tri':171,176,1156,1162 'true':178,251,320,332,334,622,634,665,701,747,767,842,864,866,929,931,1010,1165,1197,1239,1350 'turn':1005 'ui':44,385,429,567,637,708,817,884,1416 'uibackgroundmod':151,587,1335 'uikit':203,504 'uiview':284,825 'uiviewcontrol':235,282 'uiviewcontrollerrepresent':529 'undefin':1088 'unsupport':1084,1101 'updat':337,936 'url':236,237,241,242,285,286,292,293,463,464,471,472,1277,1317 'usag':431 'use':6,8,24,339,374,551,568,709,785,913,1067,1103,1294 'user':543,643,877,972,1003,1017,1189,1214,1476 'user-select':876 'var':442,445,1286,1304,1307 'version':1095 'video':11,52,351,473,485,545,845,1387,1471 'video-cap':844 'videoplay':26,76,79,191,420,422,453,488,509,1290,1311,1433 'videourl':1278,1318 'view':27,261,270,346,418,424,439,448,694,1247,1261,1269,1273,1284,1289,1301,1310,1400 'viewcontrol':234 'viewcontroller.present':248 'void':684,1233 'vs':1392 'vstack':491 'watch':544 'watermark':347 'width':498,835 'window':549 'without':136,1182 'won':1148 'work':1136,1150 'wrap':425,525 'wrong':1097,1138,1206,1265 'x':831,906 'y':833","prices":[{"id":"393e60f8-46b4-4284-b967-8843fea519d0","listingId":"5ff8341d-18f2-4df1-b2f8-a093609c0350","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:00:46.341Z"}],"sources":[{"listingId":"5ff8341d-18f2-4df1-b2f8-a093609c0350","source":"github","sourceId":"dpearson2699/swift-ios-skills/avkit","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/avkit","isPrimary":false,"firstSeenAt":"2026-04-18T22:00:46.341Z","lastSeenAt":"2026-04-22T00:53:41.682Z"}],"details":{"listingId":"5ff8341d-18f2-4df1-b2f8-a093609c0350","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"avkit","github":{"repo":"dpearson2699/swift-ios-skills","stars":468,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-21T19:26:16Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"fb8de6f5f2391b1c75b2789516b1c6b0cef36275","skill_md_path":"skills/avkit/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/avkit"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"avkit","description":"Create media playback experiences using AVKit. Use when adding video players with AVPlayerViewController, enabling Picture-in-Picture, routing media with AirPlay, using SwiftUI VideoPlayer views, configuring transport controls, displaying subtitles and closed captions, or integrating AVFoundation playback with system UI."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/avkit"},"updatedAt":"2026-04-22T00:53:41.682Z"}}