Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for tvOS Top Shelf Extensions #2793

Merged
merged 15 commits into from Jun 8, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
### Added

- Add `tuist dependencies update` command. [#2819](https://github.com/tuist/tuist/pull/2819) by [@laxmorek](https://github.com/laxmorek)
- Add `tvExtension` target product. [#2793](https://github.com/tuist/tuist/pull/2793) by [@rmnblm](https://github.com/rmnblm)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion Sources/ProjectDescription/Product.swift
Expand Up @@ -20,7 +20,7 @@ public enum Product: String, Codable, Equatable {
case watch2App
// case watchExtension
case watch2Extension
// case tvExtension
case tvExtension
// case messagesApplication
case messagesExtension
case stickerPackExtension = "sticker_pack_extension"
Expand Down
Expand Up @@ -31,8 +31,8 @@ extension Product {
// return .watchExtension
case .watch2Extension:
return .watch2Extension
// case .tvExtension:
// return .tvExtension
case .tvExtension:
return .tvExtension
// case .messagesApplication:
// return .messagesApplication
case .messagesExtension:
Expand Down
3 changes: 2 additions & 1 deletion Sources/TuistCore/ValueGraph/ValueGraphTraverser.swift
Expand Up @@ -182,7 +182,7 @@ public class ValueGraphTraverser: GraphTraversing {

public func appExtensionDependencies(path: AbsolutePath, name: String) -> Set<ValueGraphTarget> {
let validProducts: [Product] = [
.appExtension, .stickerPackExtension, .watch2Extension, .messagesExtension,
.appExtension, .stickerPackExtension, .watch2Extension, .tvExtension, .messagesExtension,
]
return Set(directLocalTargetDependencies(path: path, name: name)
.filter { validProducts.contains($0.target.product) })
Expand Down Expand Up @@ -625,6 +625,7 @@ public class ValueGraphTraverser: GraphTraversing {
.unitTests,
.uiTests,
.watch2Extension,
.tvExtension,
]
return validProducts.contains(target.product)
}
Expand Down
Expand Up @@ -111,7 +111,7 @@ final class InfoPlistContentProvider: InfoPlistContentProviding {
packageType = "FMWK"
case .watch2App, .watch2Extension:
packageType = "$(PRODUCT_BUNDLE_PACKAGE_TYPE)"
rmnblm marked this conversation as resolved.
Show resolved Hide resolved
case .appExtension, .stickerPackExtension, .messagesExtension:
case .appExtension, .stickerPackExtension, .messagesExtension, .tvExtension:
packageType = "XPC!"
case .commandLineTool:
packageType = nil
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistGenerator/GraphViz/NodeStyling.swift
Expand Up @@ -38,7 +38,7 @@ extension ValueGraphTarget {
switch target.product {
case .app, .watch2App, .commandLineTool, .appClip:
return .init(fillColorName: .deepskyblue, strokeWidth: 1.5, shape: .box3d)
case .appExtension, .watch2Extension:
case .appExtension, .watch2Extension, .tvExtension:
return .init(fillColorName: .deepskyblue2, shape: .component)
case .messagesExtension, .stickerPackExtension:
return .init(fillColorName: .springgreen2, shape: .component)
Expand Down
13 changes: 6 additions & 7 deletions Sources/TuistGenerator/Linter/GraphLinter.swift
Expand Up @@ -426,14 +426,13 @@ public class GraphLinter: GraphLinting {
LintableTarget(platform: .macOS, product: .dynamicLibrary),
LintableTarget(platform: .macOS, product: .staticFramework),
],
// tvOS
LintableTarget(platform: .tvOS, product: .app): [
LintableTarget(platform: .tvOS, product: .staticLibrary),
LintableTarget(platform: .tvOS, product: .dynamicLibrary),
LintableTarget(platform: .tvOS, product: .framework),
LintableTarget(platform: .tvOS, product: .staticFramework),
LintableTarget(platform: .tvOS, product: .bundle),
// LintableTarget(platform: .tvOS, product: .tvExtension),
LintableTarget(platform: .tvOS, product: .tvExtension),
],
LintableTarget(platform: .tvOS, product: .staticLibrary): [
LintableTarget(platform: .tvOS, product: .staticLibrary),
Expand Down Expand Up @@ -462,11 +461,11 @@ public class GraphLinter: GraphLinting {
LintableTarget(platform: .tvOS, product: .framework),
LintableTarget(platform: .tvOS, product: .staticFramework),
],
// LintableTarget(platform: .tvOS, product: .tvExtension): [
// LintableTarget(platform: .tvOS, product: .staticLibrary),
// LintableTarget(platform: .tvOS, product: .dynamicLibrary),
// LintableTarget(platform: .tvOS, product: .framework),
// ],
LintableTarget(platform: .tvOS, product: .tvExtension): [
LintableTarget(platform: .tvOS, product: .staticLibrary),
rmnblm marked this conversation as resolved.
Show resolved Hide resolved
LintableTarget(platform: .tvOS, product: .dynamicLibrary),
LintableTarget(platform: .tvOS, product: .framework),
],
// watchOS
// LintableTarget(platform: .watchOS, product: .watchApp): [
// LintableTarget(platform: .watchOS, product: .staticLibrary),
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistGenerator/Linter/TargetLinter.swift
Expand Up @@ -203,7 +203,7 @@ class TargetLinter: TargetLinting {

private func lintValidPlatformProductCombinations(target: Target) -> [LintingIssue] {
let invalidProductsForPlatforms: [Platform: [Product]] = [
.iOS: [.watch2App, .watch2Extension],
.iOS: [.watch2App, .watch2Extension, .tvExtension],
]

if let invalidProducts = invalidProductsForPlatforms[target.platform],
Expand Down
12 changes: 6 additions & 6 deletions Sources/TuistGraph/Models/Product.swift
Expand Up @@ -15,7 +15,7 @@ public enum Product: String, CustomStringConvertible, CaseIterable, Codable {
case watch2App = "watch_2_app"
// case watchExtension = "watch_extension"
case watch2Extension = "watch_2_extension"
// case tvExtension = "tv_extension"
case tvExtension = "tv_extension"
// case messagesApplication = "messages_application"
case messagesExtension = "messages_extension"
case stickerPackExtension = "sticker_pack_extension"
Expand Down Expand Up @@ -49,8 +49,8 @@ public enum Product: String, CustomStringConvertible, CaseIterable, Codable {
// return "watchExtension"
case .watch2Extension:
return "watch2Extension"
// case .tvExtension:
// return "tvExtension"
case .tvExtension:
return "tvExtension"
// case .messagesApplication:
// return "messagesApplication"
case .messagesExtension:
Expand Down Expand Up @@ -92,8 +92,8 @@ public enum Product: String, CustomStringConvertible, CaseIterable, Codable {
// return "watch extension"
case .watch2Extension:
return "watch 2 extension"
// case .tvExtension:
// return "tv extension"
case .tvExtension:
return "tv extension"
// case .messagesApplication:
// return "iMessage application"
case .messagesExtension:
Expand Down Expand Up @@ -139,7 +139,7 @@ public enum Product: String, CustomStringConvertible, CaseIterable, Codable {
}

if platform == .tvOS {
// base.append(.tvExtension)
base.append(.tvExtension)
}

if platform == .macOS ||
Expand Down
Expand Up @@ -27,6 +27,8 @@ extension TuistGraph.Product {
return .bundle
case .appExtension:
return .appExtension
case .tvExtension:
return .tvExtension
case .stickerPackExtension:
return .stickerPackExtension
case .watch2App:
Expand Down
2 changes: 1 addition & 1 deletion Tests/TuistGraphTests/Models/ProductTests.swift
Expand Up @@ -83,7 +83,7 @@ final class ProductTests: XCTestCase {
.staticLibrary,
.dynamicLibrary,
.framework,
// .tvExtension,
.tvExtension,
.unitTests,
.uiTests,
]
Expand Down
9 changes: 9 additions & 0 deletions projects/tuist/features/generate-4.feature
Expand Up @@ -43,3 +43,12 @@ Scenario: The project is an iOS application with extensions (ios_app_with_extens
Then the product 'App.app' with destination 'Debug-iphonesimulator' contains extension 'NotificationServiceExtension'
Then the product 'App.app' with destination 'Debug-iphonesimulator' contains extension 'NotificationServiceExtension'
Then the product 'App.app' with destination 'Debug-iphonesimulator' does not contain headers

Scenario: The project is a tvOS application with extensions (tvos_app_with_extensions)
Given that tuist is available
And I have a working directory
Then I copy the fixture tvos_app_with_extensions into the working directory
Then tuist generates the project
Then I should be able to build for tvOS the scheme App
Then the product 'App.app' with destination 'Debug-appletvsimulator' contains extension 'TopShelfExtension'
Then the product 'App.app' with destination 'Debug-appletvsimulator' does not contain headers
26 changes: 26 additions & 0 deletions projects/tuist/fixtures/tvos_app_with_extensions/Info.plist
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
</dict>
</plist>
36 changes: 36 additions & 0 deletions projects/tuist/fixtures/tvos_app_with_extensions/Project.swift
@@ -0,0 +1,36 @@
import ProjectDescription

let project = Project(name: "App",
targets: [
Target(name: "App",
platform: .tvOS,
product: .app,
bundleId: "io.tuist.App",
infoPlist: "Info.plist",
sources: ["Sources/**"],
dependencies: [
.target(name: "TopShelfExtension")
]),
Target(name: "TopShelfExtension",
platform: .tvOS,
product: .tvExtension,
bundleId: "io.tuist.App.TopShelfExtension",
infoPlist: .extendingDefault(with: [
"CFBundleDisplayName": "$(PRODUCT_NAME)",
"NSExtension": [
"NSExtensionPointIdentifier": "com.apple.tv-top-shelf",
"NSExtensionPrincipalClass": "$(PRODUCT_MODULE_NAME).ContentProvider"
]
]),
sources: "TopShelfExtension/**",
dependencies: [

]),
Target(name: "StaticFramework",
platform: .iOS,
product: .staticFramework,
bundleId: "io.tuist.App.StaticFramework",
infoPlist: .default,
sources: "StaticFramework/Sources/**"
)
])
@@ -0,0 +1,20 @@
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let viewController = UIViewController()
viewController.view.backgroundColor = .white
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return true
}

}
@@ -0,0 +1,7 @@
import Foundation

public struct StaticFramework {
public init() {

}
}
@@ -0,0 +1,7 @@
import TVServices

class ContentProvider: TVTopShelfContentProvider {
override func loadTopShelfContent(completionHandler: @escaping (TVTopShelfContent?) -> Void) {
rmnblm marked this conversation as resolved.
Show resolved Hide resolved

}
}