├── .gitignore
├── .DS_Store
├── Replay_.png
├── Replay
├── .DS_Store
├── Replay
│ ├── .DS_Store
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── App Icon & Top Shelf Image.brandassets
│ │ │ ├── App Icon - Large.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11_.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11_.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Middle.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11_.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── App Icon - Small.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Middle.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ ├── Replay11.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Top Shelf Image.imageset
│ │ │ │ ├── AppleTV-TopShelf-1920@1x.png
│ │ │ │ └── Contents.json
│ │ │ ├── Top Shelf Image Wide.imageset
│ │ │ │ ├── AppleTV-TopShelf-2320x.png
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ └── LaunchImage.launchimage
│ │ │ ├── ReplayLaunchImage.png
│ │ │ └── Contents.json
│ ├── BridgingHeader.h
│ ├── Info.plist
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ └── Main.storyboard
│ └── ViewController.swift
├── Replay.xcodeproj
│ ├── project.xcworkspace
│ │ ├── xcuserdata
│ │ │ ├── rajivs.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ │ └── npitchandi.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ └── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── rajivs.xcuserdatad
│ │ │ └── xcschemes
│ │ │ │ ├── xcschememanagement.plist
│ │ │ │ └── Replay.xcscheme
│ │ └── npitchandi.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── xcschememanagement.plist
│ │ │ └── Replay.xcscheme
│ └── project.pbxproj
├── ReplayTests
│ ├── Info.plist
│ └── ReplayTests.swift
└── ReplayUITests
│ ├── Info.plist
│ └── ReplayUITests.swift
├── NOTICE.txt
├── LICENSE.txt
├── CONTRIBUTING.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/.DS_Store
--------------------------------------------------------------------------------
/Replay_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay_.png
--------------------------------------------------------------------------------
/Replay/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/.DS_Store
--------------------------------------------------------------------------------
/Replay/Replay/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/.DS_Store
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/LaunchImage.launchimage/ReplayLaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/LaunchImage.launchimage/ReplayLaunchImage.png
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/project.xcworkspace/xcuserdata/rajivs.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay.xcodeproj/project.xcworkspace/xcuserdata/rajivs.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/project.xcworkspace/xcuserdata/npitchandi.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay.xcodeproj/project.xcworkspace/xcuserdata/npitchandi.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/AppleTV-TopShelf-1920@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/AppleTV-TopShelf-1920@1x.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/AppleTV-TopShelf-2320x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/AppleTV-TopShelf-2320x.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "AppleTV-TopShelf-1920@1x.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/BridgingHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // BridgingHeader.h
3 | // Replay
4 | //
5 | // Created by Rajiv Singh on 8/15/17.
6 | // Copyright © 2017 Rajiv Singh. All rights reserved.
7 | //
8 |
9 | #ifndef BridgingHeader_h
10 | #define BridgingHeader_h
11 |
12 | #import
13 |
14 | #endif /* BridgingHeader_h */
15 |
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "AppleTV-TopShelf-2320x.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Replay11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Replay11.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Replay11_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Replay11_.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Replay11_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Replay11_.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Replay11_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Replay11_.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Replay11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Replay11.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Replay11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omnissa-archive/replay-app-for-tvos/master/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Replay11.png
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11_.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11_.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "Replay11_.png",
6 | "scale" : "1x"
7 | }
8 | ],
9 | "info" : {
10 | "version" : 1,
11 | "author" : "xcode"
12 | }
13 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "landscape",
5 | "idiom" : "tv",
6 | "filename" : "ReplayLaunchImage.png",
7 | "extent" : "full-screen",
8 | "minimum-system-version" : "9.0",
9 | "scale" : "1x"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | replay-app-for-tvOS
2 |
3 | Copyright 2017 Omnissa, LLC. All Rights Reserved.
4 |
5 | This product is licensed to you under the BSD-2 license (the "License"). You may not use this product except in compliance with the BSD-2 License.
6 |
7 | This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file.
8 |
9 |
--------------------------------------------------------------------------------
/Replay/ReplayTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Replay/ReplayUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/xcuserdata/rajivs.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Replay.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 44A51DEA1F434820008A1C22
16 |
17 | primary
18 |
19 |
20 | 44A51DFB1F434820008A1C22
21 |
22 | primary
23 |
24 |
25 | 44A51E061F434820008A1C22
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Replay/Replay/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "size" : "1280x768",
5 | "idiom" : "tv",
6 | "filename" : "App Icon - Large.imagestack",
7 | "role" : "primary-app-icon"
8 | },
9 | {
10 | "size" : "400x240",
11 | "idiom" : "tv",
12 | "filename" : "App Icon - Small.imagestack",
13 | "role" : "primary-app-icon"
14 | },
15 | {
16 | "size" : "2320x720",
17 | "idiom" : "tv",
18 | "filename" : "Top Shelf Image Wide.imageset",
19 | "role" : "top-shelf-image-wide"
20 | },
21 | {
22 | "size" : "1920x720",
23 | "idiom" : "tv",
24 | "filename" : "Top Shelf Image.imageset",
25 | "role" : "top-shelf-image"
26 | }
27 | ],
28 | "info" : {
29 | "version" : 1,
30 | "author" : "xcode"
31 | }
32 | }
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/xcuserdata/npitchandi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Replay.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 44A51DEA1F434820008A1C22
16 |
17 | primary
18 |
19 |
20 | 44A51DFB1F434820008A1C22
21 |
22 | primary
23 |
24 |
25 | 44A51E061F434820008A1C22
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Replay/ReplayTests/ReplayTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReplayTests.swift
3 | // ReplayTests
4 | //
5 | // Created by Rajiv Singh on 8/15/17.
6 | // Copyright © 2017 Rajiv Singh. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Replay
11 |
12 | class ReplayTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Replay/Replay/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Replay
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | arm64
30 |
31 | UIUserInterfaceStyle
32 | Automatic
33 | NSAppTransportSecurity
34 |
35 | NSAllowsArbitraryLoads
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Replay/ReplayUITests/ReplayUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReplayUITests.swift
3 | // ReplayUITests
4 | //
5 | // Created by Rajiv Singh on 8/15/17.
6 | // Copyright © 2017 Rajiv Singh. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class ReplayUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | replay-app-for-tvOS
2 |
3 | Copyright 2017 Omnissa, LLC. All rights reserved
4 |
5 | The BSD-2 license (the "License") set forth below applies to all parts of the replay-app-for-tvOS
6 | project. You may not use this file except in compliance with the License.�
7 |
8 | BSD-2 License
9 |
10 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
11 | � Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
12 | � Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to replay-app-for-tvos
2 |
3 | The replay-app-for-tvos project team welcomes contributions from the community.
4 |
5 | ## Contribution Flow
6 |
7 | This is a rough outline of what a contributor's workflow looks like:
8 |
9 | - Create a topic branch from where you want to base your work
10 | - Make commits of logical units
11 | - Make sure your commit messages are in the proper format (see below)
12 | - Push your changes to a topic branch in your fork of the repository
13 | - Submit a pull request
14 |
15 | Example:
16 |
17 | ``` shell
18 | git remote add upstream https://github.com/omnissa-archive/replay-app-for-tvos.git
19 | git checkout -b my-new-feature master
20 | git commit -a
21 | git push origin my-new-feature
22 | ```
23 |
24 | ### Staying In Sync With Upstream
25 |
26 | When your branch gets out of sync with the omnissa-archive/master branch, use the following to update:
27 |
28 | ``` shell
29 | git checkout my-new-feature
30 | git fetch -a
31 | git pull --rebase upstream master
32 | git push --force-with-lease origin my-new-feature
33 | ```
34 |
35 | ### Updating pull requests
36 |
37 | If your PR fails to pass CI or needs changes based on code review, you'll most likely want to squash these changes into
38 | existing commits.
39 |
40 | If your pull request contains a single commit or your changes are related to the most recent commit, you can simply
41 | amend the commit.
42 |
43 | ``` shell
44 | git add .
45 | git commit --amend
46 | git push --force-with-lease origin my-new-feature
47 | ```
48 |
49 | If you need to squash changes into an earlier commit, you can use:
50 |
51 | ``` shell
52 | git add .
53 | git commit --fixup
54 | git rebase -i --autosquash master
55 | git push --force-with-lease origin my-new-feature
56 | ```
57 |
58 | Be sure to add a comment to the PR indicating your new changes are ready to review, as GitHub does not generate a
59 | notification when you git push.
60 |
61 | ### Code Style
62 |
63 | ### Formatting Commit Messages
64 |
65 | We follow the conventions on [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/).
66 |
67 | Be sure to include any related GitHub issue references in the commit message. See
68 | [GFM syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) for referencing issues
69 | and commits.
70 |
71 | ## Reporting Bugs and Creating Issues
72 |
73 | When opening a new issue, try to roughly follow the commit message format conventions above.
74 |
75 |
--------------------------------------------------------------------------------
/Replay/Replay/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Replay
4 | //
5 | // Created by Rajiv Singh and Naveen Pitchandi on 8/24/17.
6 | // Copyright 2017 Omnissa, LLC. All Rights Reserved.
7 |
8 | //This product is licensed to you under the BSD-2 license (the "License"). You may not use this product except in compliance with the BSD-2 License.
9 |
10 | //This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file.
11 |
12 |
13 | import UIKit
14 |
15 | @UIApplicationMain
16 | class AppDelegate: UIResponder, UIApplicationDelegate {
17 |
18 | var window: UIWindow?
19 |
20 |
21 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
22 | // Override point for customization after application launch.
23 | return true
24 | }
25 |
26 | func applicationWillResignActive(_ application: UIApplication) {
27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
29 | }
30 |
31 | func applicationDidEnterBackground(_ application: UIApplication) {
32 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
34 | }
35 |
36 | func applicationWillEnterForeground(_ application: UIApplication) {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 | func applicationDidBecomeActive(_ application: UIApplication) {
41 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
42 | }
43 |
44 | func applicationWillTerminate(_ application: UIApplication) {
45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
46 | }
47 |
48 |
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/Replay/Replay/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Replay
4 |
5 | tvOS application that converts an Apple TV into to a digital signage / kiosk
6 |
7 | ## Highlight Features
8 |
9 | - Plays video on launch and runs in a loop
10 | - Caches video for replay, conserving network bandwidth
11 | - Allows for airplay mirroring on top of the video and resumes once session is terminated
12 | - In conjunction with MDM, can be locked onto screen without any input from remote or remote app (on iPhone) to be a true Kiosk!
13 |
14 |
15 | ## Description
16 |
17 | The application is designed to start a video on launch and keeping running in an infinite loop. The video being played can be hosted in any public facing server. If you don't have any servers that you can host the videos on, a free AWS S3 account (Free storage up to 5GB) can be used.
18 |
19 | ## How does Replay cache videos?
20 |
21 | Videos are cached locally as application data with one complete run of the video (advise two just to be safe)
22 |
23 | ## Supported Video Formats
24 |
25 | - H.264 video up to 1080p, 30 frames per second, High or Main Profile level 4.0 or lower, Baseline profile level 3.0 or lower with AAC-LC audio up to 160 Kbps per channel, 48kHz, stereo audio in .m4v, .mp4, and .mov file formats
26 | - MPEG-4 video up to 2.5 Mbps, 640 by 480 pixels, 30 frames per second, Simple Profile with AAC-LC audio up to 160 Kbps, 48kHz, stereo audio in .m4v, .mp4, and .mov file formats
27 | - Motion JPEG (M-JPEG) up to 35 Mbps, 1280 by 720 pixels, 30 frames per second, audio in ulaw, PCM stereo audio in .avi file format
28 |
29 | ## Customization
30 |
31 | To customize the applcation for your needs, follow the steps below:
32 |
33 | STEP 1: Update the bundleID and link your Apple Developer Account
34 |
35 | STEP 2: Edit the URL for the video that you'd like to play
36 |
37 | ```
38 | // URL of the Video
39 | let media = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
40 | "
41 | ```
42 |
43 | STEP 3 (Optional): Customize the Icon and Top Shelf images
44 |
45 | Here's a [link](https://developer.apple.com/design/resources/) to Apple's design resources for template
46 | For more information on icon and top shelf images for tvOS, Refer [this] (https://developer.apple.com/tvos/human-interface-guidelines/icons-and-images/)
47 |
48 | ## Deployment
49 |
50 | Apple has made significant improvements to management capabilities of Apple TVs on tvOS 10.2 with the introduction of [DEP](https://support.apple.com/en-us/HT204142) and Enterprise Application Management.
51 |
52 | ### Enrollment
53 |
54 | - DEP on tvOS allows for a true Zero-Touch deployment with the a mode known as "Auto Advance Setup" - which when configured in the DEP profile assigned to the Apple TV, allows the Apple TV to enroll into MDM and skip all the screens to go straight to the spring board within 30seconds of network active when connected to Ethernet.
55 |
56 | Essentially, the deployment steps would be
57 | 1) Connect Apple TV to power
58 | 2) Connect to Ethernet and wait 30 seconds and watch the rest unfold
59 |
60 | *NOTE:* With the "Auto Advance Setup", do not pair the remote / tap to setup during the first 30 seconds, the key is to power on Apple TV and just wait.
61 |
62 | ### Application Management
63 |
64 | - Enterprise developed applications can now be managed for tvOS and be downloaded and installed automatically on enrollment. Replay application can hence be effectively managed using Omnissa AirWatch to transform a display to true Digital Signage
65 |
66 | ### Configuration Policies
67 |
68 | - Once the application has been installed, a configuration policy known as 'Single App Mode' with the reference of the bundle ID of this application can be deployed to the devices to automatically launch the applicaiton and lock it to the screen
69 | - In addition to the 'Single App Mode' policy, there are few more restrictions that can be added on top to enforce security such as : 1) Force incoming Airplay Requests for pairing password 2) Restrict pairing Remote app (iPhone)
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/xcuserdata/rajivs.xcuserdatad/xcschemes/Replay.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/xcuserdata/npitchandi.xcuserdatad/xcschemes/Replay.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Replay/Replay/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Replay
4 | //
5 | // Created by Rajiv Singh and Naveen Pitchandi on 8/24/17.
6 |
7 | // Copyright 2017 Omnissa, LLC. All Rights Reserved.
8 |
9 | //This product is licensed to you under the BSD-2 license (the "License"). You may not use this product except in compliance with the BSD-2 License.
10 |
11 | //This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file.
12 |
13 | import UIKit
14 | import AVFoundation
15 | import AVKit
16 |
17 | enum PlaybackState {
18 | case unknown
19 | case initializing
20 | case initialized
21 | case playing
22 | case paused
23 | case stopped
24 | case unplayable
25 | }
26 |
27 | class ViewController: UIViewController {
28 |
29 | // URL of the Video
30 | var urlArray: [String] = ["http://techslides.com/demos/sample-videos/small.mp4", "https://media.w3.org/2010/05/sintel/trailer.mp4"]
31 | var player: AVQueuePlayer? = nil
32 | var playbackStatus : PlaybackState = .unknown
33 |
34 | @IBOutlet var statusLabel : UILabel? = nil
35 |
36 | lazy var spinner = UIActivityIndicatorView.init(activityIndicatorStyle: .whiteLarge)
37 |
38 | // MARK:
39 | // MARK: View life cycle
40 |
41 | override func viewDidLoad() {
42 | super.viewDidLoad()
43 | // Do any additional setup after loading the view, typically from a nib.
44 | registerNotifications()
45 | initAudioSession()
46 | }
47 |
48 | override func viewDidAppear(_ animated: Bool) {
49 | super.viewDidAppear(animated)
50 |
51 | if playbackStatus == .unknown {
52 | playbackStatus = .initializing
53 | initPlayer()
54 | }else if playbackStatus == .playing {
55 | self.statusLabel?.text = "Player interrupted"
56 | }
57 | }
58 |
59 | // MARK:
60 | // MARK: memory management
61 |
62 | deinit {
63 | deregisterNotifications()
64 | }
65 |
66 | override func didReceiveMemoryWarning() {
67 | super.didReceiveMemoryWarning()
68 | // Dispose of any resources that can be recreated.
69 | }
70 |
71 | // MARK:
72 | // MARK: Initializations
73 |
74 | func initAudioSession() -> Void {
75 | let audioSession = AVAudioSession.sharedInstance()
76 | do {
77 | try audioSession.setCategory(AVAudioSessionCategoryPlayback)
78 | }
79 | catch {
80 | print("Setting category to AVAudioSessionCategoryPlayback failed.")
81 | }
82 | }
83 |
84 | func initPlayer() -> Void {
85 |
86 | if urlArray.isEmpty {
87 | playbackStatus = .unplayable
88 | self.statusLabel?.text = "No media specified for playback"
89 | return
90 | }
91 |
92 | let asset = assets(forMediaURLs: urlArray)
93 |
94 | guard let currentAssetPlaying = asset.first else {
95 | playbackStatus = .unplayable
96 | self.statusLabel?.text = "Could not create Assets from the supplied media URL's"
97 | return
98 | }
99 |
100 | let playableKey = "playable"
101 |
102 | // In future, we should load all assets at once and add to player queue only ones which are playable.
103 | currentAssetPlaying.loadValuesAsynchronously(forKeys: [playableKey], completionHandler: {
104 | DispatchQueue.main.async {
105 | var error: NSError? = nil
106 | let status = currentAssetPlaying.statusOfValue(forKey: playableKey, error: &error)
107 | switch status {
108 | case .loaded:
109 | // Sucessfully loaded. Continue processing.
110 | self.statusLabel?.text = "Player initialized"
111 | self.playbackStatus = .initialized
112 | self.startPlayer(forAssets: asset)
113 | break
114 | case .failed:
115 | // Handle error
116 | self.playbackStatus = .unplayable
117 | self.statusLabel?.text = "Failed to initialize the player. Error: \(error?.localizedDescription ?? "")"
118 | break
119 | case .cancelled:
120 | // Terminate processing
121 | self.playbackStatus = .unplayable
122 | self.statusLabel?.text = "Initializing player was cancelled. Error: \(error?.localizedDescription ?? "")"
123 | break
124 | default:
125 | // Handle all other cases
126 | self.playbackStatus = .unplayable
127 | self.statusLabel?.text = "Unknown error while initilizing the player"
128 | break
129 | }
130 | }
131 | })
132 | }
133 |
134 | // MARK:
135 | // MARK: Playback
136 |
137 | func startPlayer(forAssets asset: [AVURLAsset]) -> Void {
138 |
139 | if asset.isEmpty {
140 | self.playbackStatus = .unplayable
141 | self.statusLabel?.text = "Media asset not present"
142 | return
143 | }
144 |
145 | let playerItemArray = playerItemArrayCollection(forAsset: asset)
146 | if playerItemArray.isEmpty {
147 | self.playbackStatus = .unplayable
148 | self.statusLabel?.text = "Media asset not present"
149 | return
150 | }
151 |
152 | // Create a new AVPlayerViewController and pass it a reference to the player.
153 | self.player = AVQueuePlayer.init(items: playerItemArray)
154 | self.player?.actionAtItemEnd = .none
155 | if let controller = constructPlayerViewController(player: self.player) {
156 | // Modally present the player and call the player's play() method when complete.
157 | self.present(controller, animated: true) {
158 | self.playbackStatus = .playing
159 | controller.player?.play()
160 | }
161 | }
162 | }
163 |
164 | func resumePlayer(player: AVQueuePlayer?) -> Void {
165 | guard (self.playbackStatus == .playing || self.playbackStatus == .paused || self.playbackStatus == .stopped) else {
166 | return
167 | }
168 |
169 | guard player != nil else {
170 | return
171 | }
172 |
173 | if let playerViewController = self.presentedViewController as? AVPlayerViewController {
174 | playerViewController.player?.play()
175 | }else {
176 | if let controller = constructPlayerViewController(player: player) {
177 | // Modally present the player and call the player's play() method when complete.
178 | self.present(controller, animated: true) {
179 | self.playbackStatus = .playing
180 | controller.player?.play()
181 | }
182 | }
183 | }
184 | }
185 |
186 | func constructPlayerViewController(player: AVQueuePlayer?) -> AVPlayerViewController? {
187 | guard player != nil else {
188 | return nil
189 | }
190 |
191 | let controller = AVPlayerViewController()
192 | controller.showsPlaybackControls = false
193 | controller.delegate = self
194 | controller.player = player
195 | return controller
196 | }
197 |
198 | // MARK:
199 | // MARK: AVPlayer notifications
200 |
201 | func registerNotifications() -> Void {
202 | NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
203 | NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(notification:)), name: .UIApplicationDidBecomeActive, object: nil)
204 | }
205 |
206 | func deregisterNotifications() -> Void {
207 | NotificationCenter.default.removeObserver(self)
208 | }
209 |
210 | func playerItemDidReachEnd(notification: NSNotification) -> Void {
211 |
212 | guard notification.object as? AVPlayerItem == self.player?.currentItem else {
213 | return
214 | }
215 |
216 | guard let asset = self.player?.currentItem?.asset as? AVURLAsset else {
217 | return
218 | }
219 |
220 | if asset.isDownloaded() {
221 | // Asset was already downloaded. We play it again.
222 | self.player?.playNextItem()
223 | return
224 | }
225 |
226 | if asset.isExportable == false {
227 | self.player?.playNextItem()
228 | return
229 | }
230 |
231 | let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)
232 |
233 | exporter?.outputURL = asset.downloadPath(create: true)
234 | exporter?.outputFileType = AVFileTypeQuickTimeMovie
235 | exporter?.exportAsynchronously(completionHandler: {
236 | DispatchQueue.main.async {
237 | self.player?.playNextItem()
238 | return
239 | }
240 | })
241 | }
242 |
243 | func applicationDidBecomeActive(notification: Notification) -> Void {
244 | self.resumePlayer(player: self.player)
245 | }
246 |
247 | // MARK:
248 | // MARK: Spinner
249 |
250 | func showSpinner(inView parentView: UIView) -> Void {
251 | spinner.center = parentView.center
252 | parentView.addSubview(spinner)
253 | spinner.startAnimating()
254 | }
255 |
256 | func hideSpinner() -> Void {
257 | spinner.stopAnimating()
258 | spinner.removeFromSuperview()
259 | }
260 |
261 | func assets(forMediaURLs mediaURLs: [String]) -> [AVURLAsset] {
262 | var assetArray = [AVURLAsset]()
263 |
264 | for media in urlArray {
265 | guard let url = URL.init(string: media) else {
266 | continue
267 | }
268 |
269 | var asset = AVURLAsset.init(url: url, options: [AVURLAssetAllowsCellularAccessKey : false])
270 | if asset.isDownloaded() {
271 | // Asset was already downloaded before. So we recreate it from the local URL.
272 | if let localAssetURL = asset.downloadPath() {
273 | asset = AVURLAsset.init(url: localAssetURL)
274 | }
275 | }else {
276 | // Asset isn't downloaded yet. Set its resource loader so that we can export it later when its finished.
277 | asset.resourceLoader.setDelegate(self, queue: DispatchQueue.main)
278 | }
279 | assetArray.append(asset)
280 | }
281 |
282 | return assetArray
283 | }
284 |
285 | func playerItemArrayCollection(forAsset asset: [AVURLAsset]) -> [AVPlayerItem]{
286 | var playerItemArray = [AVPlayerItem]()
287 | for mediaAsset in asset{
288 | let playerItemTemp = AVPlayerItem.init(asset: mediaAsset)
289 | playerItemArray.append(playerItemTemp)
290 | }
291 | return playerItemArray
292 | }
293 |
294 | func isLastItemPlayed(asset: AVURLAsset) -> Bool {
295 | let lastURLOfMedia : String = self.urlArray.last!
296 | if(asset.url.absoluteString.range(of: lastURLOfMedia) != nil){
297 | return true
298 | }
299 | else{
300 | return false
301 | }
302 | }
303 |
304 |
305 | }
306 |
307 | // MARK:
308 | // MARK: Extensions
309 |
310 | extension AVQueuePlayer {
311 | func playNextItem(){
312 | let currentItem = self.currentItem
313 | self.advanceToNextItem()
314 |
315 | if let item = currentItem {
316 | item.seek(to: kCMTimeZero)
317 | if self.canInsert(item, after: nil){
318 | self.insert(item, after: nil)
319 | }
320 | }
321 | }
322 | }
323 | extension ViewController : AVAssetResourceLoaderDelegate {
324 | // We don't really have anything to do here.
325 | }
326 |
327 | extension ViewController : AVPlayerViewControllerDelegate {
328 | func playerViewController(_ playerViewController: AVPlayerViewController, shouldPresent proposal: AVContentProposal, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
329 | self.present(playerViewController, animated: true) {
330 | completionHandler(true)
331 | }
332 | }
333 | }
334 |
335 | extension AVPlayer {
336 | func restart() -> Void {
337 | self.pause()
338 | self.seek(to: kCMTimeZero)
339 | self.play()
340 | }
341 | }
342 |
343 | extension AVURLAsset {
344 |
345 | func isDownloaded() -> Bool {
346 |
347 | // First check if media is present at asset's URL. This could be the case if asset was created locally.
348 | let mediaExists = FileManager.init().fileExists(atPath: self.url.path)
349 | if mediaExists == false {
350 | // Media is not present at asset's URL. Derive the download path to check if its present there instead.
351 | if let downloadedAssetURL = self.downloadPath() {
352 | let mediaExists = FileManager.init().fileExists(atPath: downloadedAssetURL.path)
353 | return mediaExists
354 | }
355 | }else {
356 | // Media is present at asset's URL. This means asset was created out of the locally stored media. Thus, it is already downloaded.
357 | return true
358 | }
359 |
360 | return false
361 | }
362 |
363 | func downloadPath(create: Bool = false) -> URL? {
364 |
365 | let urlData = self.url.absoluteString.data(using: .utf8)
366 | let base64EncodedString = urlData?.base64EncodedString()
367 |
368 | guard let urlDirectory = base64EncodedString else {
369 | return nil
370 | }
371 |
372 | guard let documentsDirectory: URL = FileManager.init().urls(for: FileManager.SearchPathDirectory.cachesDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).last else {
373 | return nil
374 | }
375 |
376 | let directoryURL = documentsDirectory.appendingPathComponent(urlDirectory)
377 |
378 | if create {
379 | do {
380 | try FileManager.init().createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
381 | }catch let error as NSError {
382 | print("Failed to create asset’s download path with error: \(error.localizedDescription)")
383 | }
384 | }
385 | let fileExtension = ".mov"
386 | let filename = "\(urlDirectory)\(fileExtension)"
387 | let mediaURL = directoryURL.appendingPathComponent(filename)
388 | return mediaURL
389 | }
390 | }
391 |
392 | extension String {
393 | func sha512() -> String? {
394 | if let stringData = self.data(using: String.Encoding.utf8) {
395 | if let hash = stringData.sha512() {
396 | return hash.base64EncodedString()
397 | }
398 | }
399 | return nil
400 | }
401 | }
402 |
403 | extension Data {
404 | func sha512() -> Data? {
405 |
406 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH))
407 | self.withUnsafeBytes {
408 | _ = CC_SHA512($0, CC_LONG(self.count), &hash)
409 | }
410 | return Data(bytes: hash)
411 |
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/Replay/Replay.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 01AB047F1F4F9F27007A4985 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 44A51DF51F434820008A1C22 /* Assets.xcassets */; };
11 | 44A51DEF1F434820008A1C22 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A51DEE1F434820008A1C22 /* AppDelegate.swift */; };
12 | 44A51DF11F434820008A1C22 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A51DF01F434820008A1C22 /* ViewController.swift */; };
13 | 44A51DF41F434820008A1C22 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 44A51DF21F434820008A1C22 /* Main.storyboard */; };
14 | 44A51E011F434820008A1C22 /* ReplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A51E001F434820008A1C22 /* ReplayTests.swift */; };
15 | 44A51E0C1F434820008A1C22 /* ReplayUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A51E0B1F434820008A1C22 /* ReplayUITests.swift */; };
16 | 44A51E1B1F4348BC008A1C22 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 44A51E1A1F4348BC008A1C22 /* AVFoundation.framework */; };
17 | 44A51E1D1F4348C2008A1C22 /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 44A51E1C1F4348C2008A1C22 /* AVKit.framework */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 44A51DFD1F434820008A1C22 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 44A51DE31F434820008A1C22 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 44A51DEA1F434820008A1C22;
26 | remoteInfo = Replay;
27 | };
28 | 44A51E081F434820008A1C22 /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 44A51DE31F434820008A1C22 /* Project object */;
31 | proxyType = 1;
32 | remoteGlobalIDString = 44A51DEA1F434820008A1C22;
33 | remoteInfo = Replay;
34 | };
35 | /* End PBXContainerItemProxy section */
36 |
37 | /* Begin PBXFileReference section */
38 | 44A51DEB1F434820008A1C22 /* Replay.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Replay.app; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 44A51DEE1F434820008A1C22 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 44A51DF01F434820008A1C22 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
41 | 44A51DF31F434820008A1C22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 44A51DF51F434820008A1C22 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 44A51DF71F434820008A1C22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
44 | 44A51DFC1F434820008A1C22 /* ReplayTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReplayTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
45 | 44A51E001F434820008A1C22 /* ReplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplayTests.swift; sourceTree = ""; };
46 | 44A51E021F434820008A1C22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | 44A51E071F434820008A1C22 /* ReplayUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReplayUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 44A51E0B1F434820008A1C22 /* ReplayUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplayUITests.swift; sourceTree = ""; };
49 | 44A51E0D1F434820008A1C22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | 44A51E1A1F4348BC008A1C22 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
51 | 44A51E1C1F4348C2008A1C22 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; };
52 | 44A51E1E1F4349DD008A1C22 /* BridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 44A51DE81F434820008A1C22 /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | 44A51E1D1F4348C2008A1C22 /* AVKit.framework in Frameworks */,
61 | 44A51E1B1F4348BC008A1C22 /* AVFoundation.framework in Frameworks */,
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | 44A51DF91F434820008A1C22 /* Frameworks */ = {
66 | isa = PBXFrameworksBuildPhase;
67 | buildActionMask = 2147483647;
68 | files = (
69 | );
70 | runOnlyForDeploymentPostprocessing = 0;
71 | };
72 | 44A51E041F434820008A1C22 /* Frameworks */ = {
73 | isa = PBXFrameworksBuildPhase;
74 | buildActionMask = 2147483647;
75 | files = (
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | /* End PBXFrameworksBuildPhase section */
80 |
81 | /* Begin PBXGroup section */
82 | 44A51DE21F434820008A1C22 = {
83 | isa = PBXGroup;
84 | children = (
85 | 44A51DED1F434820008A1C22 /* Replay */,
86 | 44A51DFF1F434820008A1C22 /* ReplayTests */,
87 | 44A51E0A1F434820008A1C22 /* ReplayUITests */,
88 | 44A51DEC1F434820008A1C22 /* Products */,
89 | 44A51E191F4348BC008A1C22 /* Frameworks */,
90 | );
91 | sourceTree = "";
92 | };
93 | 44A51DEC1F434820008A1C22 /* Products */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 44A51DEB1F434820008A1C22 /* Replay.app */,
97 | 44A51DFC1F434820008A1C22 /* ReplayTests.xctest */,
98 | 44A51E071F434820008A1C22 /* ReplayUITests.xctest */,
99 | );
100 | name = Products;
101 | sourceTree = "";
102 | };
103 | 44A51DED1F434820008A1C22 /* Replay */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 44A51DEE1F434820008A1C22 /* AppDelegate.swift */,
107 | 44A51DF01F434820008A1C22 /* ViewController.swift */,
108 | 44A51DF21F434820008A1C22 /* Main.storyboard */,
109 | 44A51DF51F434820008A1C22 /* Assets.xcassets */,
110 | 44A51E1E1F4349DD008A1C22 /* BridgingHeader.h */,
111 | 44A51DF71F434820008A1C22 /* Info.plist */,
112 | );
113 | path = Replay;
114 | sourceTree = "";
115 | };
116 | 44A51DFF1F434820008A1C22 /* ReplayTests */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 44A51E001F434820008A1C22 /* ReplayTests.swift */,
120 | 44A51E021F434820008A1C22 /* Info.plist */,
121 | );
122 | path = ReplayTests;
123 | sourceTree = "";
124 | };
125 | 44A51E0A1F434820008A1C22 /* ReplayUITests */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 44A51E0B1F434820008A1C22 /* ReplayUITests.swift */,
129 | 44A51E0D1F434820008A1C22 /* Info.plist */,
130 | );
131 | path = ReplayUITests;
132 | sourceTree = "";
133 | };
134 | 44A51E191F4348BC008A1C22 /* Frameworks */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 44A51E1C1F4348C2008A1C22 /* AVKit.framework */,
138 | 44A51E1A1F4348BC008A1C22 /* AVFoundation.framework */,
139 | );
140 | name = Frameworks;
141 | sourceTree = "";
142 | };
143 | /* End PBXGroup section */
144 |
145 | /* Begin PBXNativeTarget section */
146 | 44A51DEA1F434820008A1C22 /* Replay */ = {
147 | isa = PBXNativeTarget;
148 | buildConfigurationList = 44A51E101F434820008A1C22 /* Build configuration list for PBXNativeTarget "Replay" */;
149 | buildPhases = (
150 | 44A51DE71F434820008A1C22 /* Sources */,
151 | 44A51DE81F434820008A1C22 /* Frameworks */,
152 | 44A51DE91F434820008A1C22 /* Resources */,
153 | );
154 | buildRules = (
155 | );
156 | dependencies = (
157 | );
158 | name = Replay;
159 | productName = Replay;
160 | productReference = 44A51DEB1F434820008A1C22 /* Replay.app */;
161 | productType = "com.apple.product-type.application";
162 | };
163 | 44A51DFB1F434820008A1C22 /* ReplayTests */ = {
164 | isa = PBXNativeTarget;
165 | buildConfigurationList = 44A51E131F434820008A1C22 /* Build configuration list for PBXNativeTarget "ReplayTests" */;
166 | buildPhases = (
167 | 44A51DF81F434820008A1C22 /* Sources */,
168 | 44A51DF91F434820008A1C22 /* Frameworks */,
169 | 44A51DFA1F434820008A1C22 /* Resources */,
170 | );
171 | buildRules = (
172 | );
173 | dependencies = (
174 | 44A51DFE1F434820008A1C22 /* PBXTargetDependency */,
175 | );
176 | name = ReplayTests;
177 | productName = ReplayTests;
178 | productReference = 44A51DFC1F434820008A1C22 /* ReplayTests.xctest */;
179 | productType = "com.apple.product-type.bundle.unit-test";
180 | };
181 | 44A51E061F434820008A1C22 /* ReplayUITests */ = {
182 | isa = PBXNativeTarget;
183 | buildConfigurationList = 44A51E161F434820008A1C22 /* Build configuration list for PBXNativeTarget "ReplayUITests" */;
184 | buildPhases = (
185 | 44A51E031F434820008A1C22 /* Sources */,
186 | 44A51E041F434820008A1C22 /* Frameworks */,
187 | 44A51E051F434820008A1C22 /* Resources */,
188 | );
189 | buildRules = (
190 | );
191 | dependencies = (
192 | 44A51E091F434820008A1C22 /* PBXTargetDependency */,
193 | );
194 | name = ReplayUITests;
195 | productName = ReplayUITests;
196 | productReference = 44A51E071F434820008A1C22 /* ReplayUITests.xctest */;
197 | productType = "com.apple.product-type.bundle.ui-testing";
198 | };
199 | /* End PBXNativeTarget section */
200 |
201 | /* Begin PBXProject section */
202 | 44A51DE31F434820008A1C22 /* Project object */ = {
203 | isa = PBXProject;
204 | attributes = {
205 | LastSwiftUpdateCheck = 0830;
206 | LastUpgradeCheck = 0830;
207 | ORGANIZATIONNAME = Omnissa;
208 | TargetAttributes = {
209 | 44A51DEA1F434820008A1C22 = {
210 | CreatedOnToolsVersion = 8.3.3;
211 | DevelopmentTeam = 7SUQPKEF96;
212 | ProvisioningStyle = Automatic;
213 | };
214 | 44A51DFB1F434820008A1C22 = {
215 | CreatedOnToolsVersion = 8.3.3;
216 | DevelopmentTeam = S2ZMFGQM93;
217 | ProvisioningStyle = Automatic;
218 | TestTargetID = 44A51DEA1F434820008A1C22;
219 | };
220 | 44A51E061F434820008A1C22 = {
221 | CreatedOnToolsVersion = 8.3.3;
222 | DevelopmentTeam = S2ZMFGQM93;
223 | ProvisioningStyle = Automatic;
224 | TestTargetID = 44A51DEA1F434820008A1C22;
225 | };
226 | };
227 | };
228 | buildConfigurationList = 44A51DE61F434820008A1C22 /* Build configuration list for PBXProject "Replay" */;
229 | compatibilityVersion = "Xcode 3.2";
230 | developmentRegion = English;
231 | hasScannedForEncodings = 0;
232 | knownRegions = (
233 | en,
234 | Base,
235 | );
236 | mainGroup = 44A51DE21F434820008A1C22;
237 | productRefGroup = 44A51DEC1F434820008A1C22 /* Products */;
238 | projectDirPath = "";
239 | projectRoot = "";
240 | targets = (
241 | 44A51DEA1F434820008A1C22 /* Replay */,
242 | 44A51DFB1F434820008A1C22 /* ReplayTests */,
243 | 44A51E061F434820008A1C22 /* ReplayUITests */,
244 | );
245 | };
246 | /* End PBXProject section */
247 |
248 | /* Begin PBXResourcesBuildPhase section */
249 | 44A51DE91F434820008A1C22 /* Resources */ = {
250 | isa = PBXResourcesBuildPhase;
251 | buildActionMask = 2147483647;
252 | files = (
253 | 01AB047F1F4F9F27007A4985 /* Assets.xcassets in Resources */,
254 | 44A51DF41F434820008A1C22 /* Main.storyboard in Resources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | 44A51DFA1F434820008A1C22 /* Resources */ = {
259 | isa = PBXResourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | );
263 | runOnlyForDeploymentPostprocessing = 0;
264 | };
265 | 44A51E051F434820008A1C22 /* Resources */ = {
266 | isa = PBXResourcesBuildPhase;
267 | buildActionMask = 2147483647;
268 | files = (
269 | );
270 | runOnlyForDeploymentPostprocessing = 0;
271 | };
272 | /* End PBXResourcesBuildPhase section */
273 |
274 | /* Begin PBXSourcesBuildPhase section */
275 | 44A51DE71F434820008A1C22 /* Sources */ = {
276 | isa = PBXSourcesBuildPhase;
277 | buildActionMask = 2147483647;
278 | files = (
279 | 44A51DF11F434820008A1C22 /* ViewController.swift in Sources */,
280 | 44A51DEF1F434820008A1C22 /* AppDelegate.swift in Sources */,
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | };
284 | 44A51DF81F434820008A1C22 /* Sources */ = {
285 | isa = PBXSourcesBuildPhase;
286 | buildActionMask = 2147483647;
287 | files = (
288 | 44A51E011F434820008A1C22 /* ReplayTests.swift in Sources */,
289 | );
290 | runOnlyForDeploymentPostprocessing = 0;
291 | };
292 | 44A51E031F434820008A1C22 /* Sources */ = {
293 | isa = PBXSourcesBuildPhase;
294 | buildActionMask = 2147483647;
295 | files = (
296 | 44A51E0C1F434820008A1C22 /* ReplayUITests.swift in Sources */,
297 | );
298 | runOnlyForDeploymentPostprocessing = 0;
299 | };
300 | /* End PBXSourcesBuildPhase section */
301 |
302 | /* Begin PBXTargetDependency section */
303 | 44A51DFE1F434820008A1C22 /* PBXTargetDependency */ = {
304 | isa = PBXTargetDependency;
305 | target = 44A51DEA1F434820008A1C22 /* Replay */;
306 | targetProxy = 44A51DFD1F434820008A1C22 /* PBXContainerItemProxy */;
307 | };
308 | 44A51E091F434820008A1C22 /* PBXTargetDependency */ = {
309 | isa = PBXTargetDependency;
310 | target = 44A51DEA1F434820008A1C22 /* Replay */;
311 | targetProxy = 44A51E081F434820008A1C22 /* PBXContainerItemProxy */;
312 | };
313 | /* End PBXTargetDependency section */
314 |
315 | /* Begin PBXVariantGroup section */
316 | 44A51DF21F434820008A1C22 /* Main.storyboard */ = {
317 | isa = PBXVariantGroup;
318 | children = (
319 | 44A51DF31F434820008A1C22 /* Base */,
320 | );
321 | name = Main.storyboard;
322 | sourceTree = "";
323 | };
324 | /* End PBXVariantGroup section */
325 |
326 | /* Begin XCBuildConfiguration section */
327 | 44A51E0E1F434820008A1C22 /* Debug */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ALWAYS_SEARCH_USER_PATHS = NO;
331 | CLANG_ANALYZER_NONNULL = YES;
332 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
334 | CLANG_CXX_LIBRARY = "libc++";
335 | CLANG_ENABLE_MODULES = YES;
336 | CLANG_ENABLE_OBJC_ARC = YES;
337 | CLANG_WARN_BOOL_CONVERSION = YES;
338 | CLANG_WARN_CONSTANT_CONVERSION = YES;
339 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
340 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
341 | CLANG_WARN_EMPTY_BODY = YES;
342 | CLANG_WARN_ENUM_CONVERSION = YES;
343 | CLANG_WARN_INFINITE_RECURSION = YES;
344 | CLANG_WARN_INT_CONVERSION = YES;
345 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNREACHABLE_CODE = YES;
348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
349 | COPY_PHASE_STRIP = NO;
350 | DEBUG_INFORMATION_FORMAT = dwarf;
351 | ENABLE_STRICT_OBJC_MSGSEND = YES;
352 | ENABLE_TESTABILITY = YES;
353 | GCC_C_LANGUAGE_STANDARD = gnu99;
354 | GCC_DYNAMIC_NO_PIC = NO;
355 | GCC_NO_COMMON_BLOCKS = YES;
356 | GCC_OPTIMIZATION_LEVEL = 0;
357 | GCC_PREPROCESSOR_DEFINITIONS = (
358 | "DEBUG=1",
359 | "$(inherited)",
360 | );
361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
363 | GCC_WARN_UNDECLARED_SELECTOR = YES;
364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
365 | GCC_WARN_UNUSED_FUNCTION = YES;
366 | GCC_WARN_UNUSED_VARIABLE = YES;
367 | MTL_ENABLE_DEBUG_INFO = YES;
368 | ONLY_ACTIVE_ARCH = YES;
369 | SDKROOT = appletvos;
370 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
371 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
372 | TARGETED_DEVICE_FAMILY = 3;
373 | TVOS_DEPLOYMENT_TARGET = 10.2;
374 | };
375 | name = Debug;
376 | };
377 | 44A51E0F1F434820008A1C22 /* Release */ = {
378 | isa = XCBuildConfiguration;
379 | buildSettings = {
380 | ALWAYS_SEARCH_USER_PATHS = NO;
381 | CLANG_ANALYZER_NONNULL = YES;
382 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
383 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
384 | CLANG_CXX_LIBRARY = "libc++";
385 | CLANG_ENABLE_MODULES = YES;
386 | CLANG_ENABLE_OBJC_ARC = YES;
387 | CLANG_WARN_BOOL_CONVERSION = YES;
388 | CLANG_WARN_CONSTANT_CONVERSION = YES;
389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
390 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
391 | CLANG_WARN_EMPTY_BODY = YES;
392 | CLANG_WARN_ENUM_CONVERSION = YES;
393 | CLANG_WARN_INFINITE_RECURSION = YES;
394 | CLANG_WARN_INT_CONVERSION = YES;
395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
396 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
397 | CLANG_WARN_UNREACHABLE_CODE = YES;
398 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
399 | COPY_PHASE_STRIP = NO;
400 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
401 | ENABLE_NS_ASSERTIONS = NO;
402 | ENABLE_STRICT_OBJC_MSGSEND = YES;
403 | GCC_C_LANGUAGE_STANDARD = gnu99;
404 | GCC_NO_COMMON_BLOCKS = YES;
405 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
406 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
407 | GCC_WARN_UNDECLARED_SELECTOR = YES;
408 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
409 | GCC_WARN_UNUSED_FUNCTION = YES;
410 | GCC_WARN_UNUSED_VARIABLE = YES;
411 | MTL_ENABLE_DEBUG_INFO = NO;
412 | SDKROOT = appletvos;
413 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
414 | TARGETED_DEVICE_FAMILY = 3;
415 | TVOS_DEPLOYMENT_TARGET = 10.2;
416 | VALIDATE_PRODUCT = YES;
417 | };
418 | name = Release;
419 | };
420 | 44A51E111F434820008A1C22 /* Debug */ = {
421 | isa = XCBuildConfiguration;
422 | buildSettings = {
423 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
424 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
425 | DEVELOPMENT_TEAM = 7SUQPKEF96;
426 | INFOPLIST_FILE = Replay/Info.plist;
427 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
428 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.Replay";
429 | PRODUCT_NAME = "$(TARGET_NAME)";
430 | SWIFT_OBJC_BRIDGING_HEADER = Replay/BridgingHeader.h;
431 | SWIFT_VERSION = 3.0;
432 | };
433 | name = Debug;
434 | };
435 | 44A51E121F434820008A1C22 /* Release */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
439 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
440 | DEVELOPMENT_TEAM = 7SUQPKEF96;
441 | INFOPLIST_FILE = Replay/Info.plist;
442 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
443 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.Replay";
444 | PRODUCT_NAME = "$(TARGET_NAME)";
445 | SWIFT_OBJC_BRIDGING_HEADER = Replay/BridgingHeader.h;
446 | SWIFT_VERSION = 3.0;
447 | };
448 | name = Release;
449 | };
450 | 44A51E141F434820008A1C22 /* Debug */ = {
451 | isa = XCBuildConfiguration;
452 | buildSettings = {
453 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
454 | BUNDLE_LOADER = "$(TEST_HOST)";
455 | DEVELOPMENT_TEAM = S2ZMFGQM93;
456 | INFOPLIST_FILE = ReplayTests/Info.plist;
457 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
458 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.ReplayTests";
459 | PRODUCT_NAME = "$(TARGET_NAME)";
460 | SWIFT_VERSION = 3.0;
461 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Replay.app/Replay";
462 | };
463 | name = Debug;
464 | };
465 | 44A51E151F434820008A1C22 /* Release */ = {
466 | isa = XCBuildConfiguration;
467 | buildSettings = {
468 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
469 | BUNDLE_LOADER = "$(TEST_HOST)";
470 | DEVELOPMENT_TEAM = S2ZMFGQM93;
471 | INFOPLIST_FILE = ReplayTests/Info.plist;
472 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
473 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.ReplayTests";
474 | PRODUCT_NAME = "$(TARGET_NAME)";
475 | SWIFT_VERSION = 3.0;
476 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Replay.app/Replay";
477 | };
478 | name = Release;
479 | };
480 | 44A51E171F434820008A1C22 /* Debug */ = {
481 | isa = XCBuildConfiguration;
482 | buildSettings = {
483 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
484 | DEVELOPMENT_TEAM = S2ZMFGQM93;
485 | INFOPLIST_FILE = ReplayUITests/Info.plist;
486 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
487 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.ReplayUITests";
488 | PRODUCT_NAME = "$(TARGET_NAME)";
489 | SWIFT_VERSION = 3.0;
490 | TEST_TARGET_NAME = Replay;
491 | };
492 | name = Debug;
493 | };
494 | 44A51E181F434820008A1C22 /* Release */ = {
495 | isa = XCBuildConfiguration;
496 | buildSettings = {
497 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
498 | DEVELOPMENT_TEAM = S2ZMFGQM93;
499 | INFOPLIST_FILE = ReplayUITests/Info.plist;
500 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
501 | PRODUCT_BUNDLE_IDENTIFIER = "com.air-watch.ReplayUITests";
502 | PRODUCT_NAME = "$(TARGET_NAME)";
503 | SWIFT_VERSION = 3.0;
504 | TEST_TARGET_NAME = Replay;
505 | };
506 | name = Release;
507 | };
508 | /* End XCBuildConfiguration section */
509 |
510 | /* Begin XCConfigurationList section */
511 | 44A51DE61F434820008A1C22 /* Build configuration list for PBXProject "Replay" */ = {
512 | isa = XCConfigurationList;
513 | buildConfigurations = (
514 | 44A51E0E1F434820008A1C22 /* Debug */,
515 | 44A51E0F1F434820008A1C22 /* Release */,
516 | );
517 | defaultConfigurationIsVisible = 0;
518 | defaultConfigurationName = Release;
519 | };
520 | 44A51E101F434820008A1C22 /* Build configuration list for PBXNativeTarget "Replay" */ = {
521 | isa = XCConfigurationList;
522 | buildConfigurations = (
523 | 44A51E111F434820008A1C22 /* Debug */,
524 | 44A51E121F434820008A1C22 /* Release */,
525 | );
526 | defaultConfigurationIsVisible = 0;
527 | defaultConfigurationName = Release;
528 | };
529 | 44A51E131F434820008A1C22 /* Build configuration list for PBXNativeTarget "ReplayTests" */ = {
530 | isa = XCConfigurationList;
531 | buildConfigurations = (
532 | 44A51E141F434820008A1C22 /* Debug */,
533 | 44A51E151F434820008A1C22 /* Release */,
534 | );
535 | defaultConfigurationIsVisible = 0;
536 | defaultConfigurationName = Release;
537 | };
538 | 44A51E161F434820008A1C22 /* Build configuration list for PBXNativeTarget "ReplayUITests" */ = {
539 | isa = XCConfigurationList;
540 | buildConfigurations = (
541 | 44A51E171F434820008A1C22 /* Debug */,
542 | 44A51E181F434820008A1C22 /* Release */,
543 | );
544 | defaultConfigurationIsVisible = 0;
545 | defaultConfigurationName = Release;
546 | };
547 | /* End XCConfigurationList section */
548 | };
549 | rootObject = 44A51DE31F434820008A1C22 /* Project object */;
550 | }
551 |
--------------------------------------------------------------------------------