mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge pull request #7566 from vector-im/mauroromito/broadcast_extension
Broadcast Upload Extension
This commit is contained in:
commit
c87b8e25e1
23 changed files with 767 additions and 0 deletions
30
BroadcastUploadExtension/Common.xcconfig
Normal file
30
BroadcastUploadExtension/Common.xcconfig
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Copyright 2023 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Config/AppIdentifiers.xcconfig"
|
||||||
|
#include "Config/AppVersion.xcconfig"
|
||||||
|
|
||||||
|
PRODUCT_NAME = BroadcastUploadExtension
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = $(BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER)
|
||||||
|
|
||||||
|
INFOPLIST_FILE = BroadcastUploadExtension/SupportingFiles/Info.plist
|
||||||
|
|
||||||
|
CODE_SIGN_ENTITLEMENTS = BroadcastUploadExtension/SupportingFiles/BroadcastUploadExtension.entitlements
|
||||||
|
|
||||||
|
SKIP_INSTALL = YES
|
21
BroadcastUploadExtension/Debug.xcconfig
Normal file
21
BroadcastUploadExtension/Debug.xcconfig
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Copyright 2020 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Common.xcconfig"
|
||||||
|
#include "Pods/Target Support Files/Pods-RiotPods-BroadcastUploadExtension/Pods-RiotPods-BroadcastUploadExtension.debug.xcconfig"
|
26
BroadcastUploadExtension/Release.xcconfig
Normal file
26
BroadcastUploadExtension/Release.xcconfig
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// Copyright 2020 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Common.xcconfig"
|
||||||
|
#include "Pods/Target Support Files/Pods-RiotPods-BroadcastUploadExtension/Pods-RiotPods-BroadcastUploadExtension.release.xcconfig"
|
||||||
|
|
||||||
|
PROVISIONING_PROFILE = $(BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE)
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = $(BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER)
|
||||||
|
|
||||||
|
COPY_PHASE_STRIP = NO
|
41
BroadcastUploadExtension/Sources/Atomic.swift
Normal file
41
BroadcastUploadExtension/Sources/Atomic.swift
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// License from the original repository:
|
||||||
|
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
|
||||||
|
|
||||||
|
//
|
||||||
|
// Atomic.swift
|
||||||
|
// Broadcast Extension
|
||||||
|
//
|
||||||
|
// Created by Maksym Shcheglov.
|
||||||
|
// https://www.onswiftwings.com/posts/atomic-property-wrapper/
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@propertyWrapper
|
||||||
|
struct Atomic<Value> {
|
||||||
|
|
||||||
|
private var value: Value
|
||||||
|
private let lock = NSLock()
|
||||||
|
|
||||||
|
init(wrappedValue value: Value) {
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrappedValue: Value {
|
||||||
|
get { load() }
|
||||||
|
set { store(newValue: newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func load() -> Value {
|
||||||
|
lock.lock()
|
||||||
|
defer { lock.unlock() }
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func store(newValue: Value) {
|
||||||
|
lock.lock()
|
||||||
|
defer { lock.unlock() }
|
||||||
|
value = newValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// License from the original repository:
|
||||||
|
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
|
||||||
|
|
||||||
|
//
|
||||||
|
// DarwinNotificationCenter.swift
|
||||||
|
// Broadcast Extension
|
||||||
|
//
|
||||||
|
// Created by Alex-Dan Bumbu on 23/03/2021.
|
||||||
|
// Copyright © 2021 8x8, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum DarwinNotification: String {
|
||||||
|
case broadcastStarted = "iOS_BroadcastStarted"
|
||||||
|
case broadcastStopped = "iOS_BroadcastStopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
class DarwinNotificationCenter {
|
||||||
|
|
||||||
|
static let shared = DarwinNotificationCenter()
|
||||||
|
|
||||||
|
private let notificationCenter: CFNotificationCenter
|
||||||
|
|
||||||
|
init() {
|
||||||
|
notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func postNotification(_ name: DarwinNotification) {
|
||||||
|
CFNotificationCenterPostNotification(notificationCenter, CFNotificationName(rawValue: name.rawValue as CFString), nil, nil, true)
|
||||||
|
}
|
||||||
|
}
|
125
BroadcastUploadExtension/Sources/SampleHandler.swift
Normal file
125
BroadcastUploadExtension/Sources/SampleHandler.swift
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
//
|
||||||
|
// License from the original repository:
|
||||||
|
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
|
||||||
|
//
|
||||||
|
// SampleHandler.swift
|
||||||
|
// Broadcast Extension
|
||||||
|
//
|
||||||
|
// Created by Alex-Dan Bumbu on 04.06.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReplayKit
|
||||||
|
|
||||||
|
import MatrixSDK
|
||||||
|
|
||||||
|
private enum Constants {
|
||||||
|
// the App Group ID value that the app and the broadcast extension targets are setup with. It differs for each app.
|
||||||
|
static let appGroupIdentifier = BuildSettings.applicationGroupIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleHandler: RPBroadcastSampleHandler {
|
||||||
|
|
||||||
|
private var clientConnection: SocketConnection?
|
||||||
|
private var uploader: SampleUploader?
|
||||||
|
|
||||||
|
private var frameCount: Int = 0
|
||||||
|
|
||||||
|
private var socketFilePath: String {
|
||||||
|
let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
|
||||||
|
return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
setupLogger()
|
||||||
|
|
||||||
|
if let connection = SocketConnection(filePath: socketFilePath) {
|
||||||
|
clientConnection = connection
|
||||||
|
setupConnection()
|
||||||
|
|
||||||
|
uploader = SampleUploader(connection: connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
|
||||||
|
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
|
||||||
|
frameCount = 0
|
||||||
|
|
||||||
|
DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
|
||||||
|
openConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func broadcastPaused() {
|
||||||
|
// User has requested to pause the broadcast. Samples will stop being delivered.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func broadcastResumed() {
|
||||||
|
// User has requested to resume the broadcast. Samples delivery will resume.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func broadcastFinished() {
|
||||||
|
// User has requested to finish the broadcast.
|
||||||
|
DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
|
||||||
|
clientConnection?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
|
||||||
|
switch sampleBufferType {
|
||||||
|
case RPSampleBufferType.video:
|
||||||
|
// very simple mechanism for adjusting frame rate by using every third frame
|
||||||
|
frameCount += 1
|
||||||
|
if frameCount % 3 == 0 {
|
||||||
|
uploader?.send(sample: sampleBuffer)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension SampleHandler {
|
||||||
|
|
||||||
|
func setupConnection() {
|
||||||
|
clientConnection?.didClose = { [weak self] error in
|
||||||
|
MXLog.error("client connection did close", context: error)
|
||||||
|
|
||||||
|
if let error = error {
|
||||||
|
self?.finishBroadcastWithError(error)
|
||||||
|
} else {
|
||||||
|
// the displayed failure message is more user friendly when using NSError instead of Error
|
||||||
|
let JMScreenSharingStopped = 10001
|
||||||
|
let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: "Screen sharing stopped"])
|
||||||
|
self?.finishBroadcastWithError(customError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openConnection() {
|
||||||
|
let queue = DispatchQueue(label: "broadcast.connectTimer")
|
||||||
|
let timer = DispatchSource.makeTimerSource(queue: queue)
|
||||||
|
timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
|
||||||
|
timer.setEventHandler { [weak self] in
|
||||||
|
guard self?.clientConnection?.open() == true else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLogger() {
|
||||||
|
let configuration = MXLogConfiguration()
|
||||||
|
configuration.logLevel = .verbose
|
||||||
|
configuration.maxLogFilesCount = 100
|
||||||
|
configuration.logFilesSizeLimit = 10 * 1024 * 1024; // 10MB
|
||||||
|
configuration.subLogName = "broadcastUploadExtension"
|
||||||
|
|
||||||
|
if isatty(STDERR_FILENO) == 0 {
|
||||||
|
configuration.redirectLogsToFiles = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MXLog.configure(configuration)
|
||||||
|
}
|
||||||
|
}
|
151
BroadcastUploadExtension/Sources/SampleUploader.swift
Normal file
151
BroadcastUploadExtension/Sources/SampleUploader.swift
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
//
|
||||||
|
// License from the original repository:
|
||||||
|
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
|
||||||
|
//
|
||||||
|
// SampleUploader.swift
|
||||||
|
// Broadcast Extension
|
||||||
|
//
|
||||||
|
// Created by Alex-Dan Bumbu on 22/03/2021.
|
||||||
|
// Copyright © 2021 8x8, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ReplayKit
|
||||||
|
|
||||||
|
import MatrixSDK
|
||||||
|
|
||||||
|
private enum Constants {
|
||||||
|
static let bufferMaxLength = 10240
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleUploader {
|
||||||
|
|
||||||
|
private static var imageContext = CIContext(options: nil)
|
||||||
|
|
||||||
|
@Atomic private var isReady = false
|
||||||
|
private var connection: SocketConnection
|
||||||
|
|
||||||
|
private var dataToSend: Data?
|
||||||
|
private var byteIndex = 0
|
||||||
|
|
||||||
|
private let serialQueue: DispatchQueue
|
||||||
|
|
||||||
|
init(connection: SocketConnection) {
|
||||||
|
self.connection = connection
|
||||||
|
self.serialQueue = DispatchQueue(label: "org.jitsi.meet.broadcast.sampleUploader")
|
||||||
|
|
||||||
|
setupConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult func send(sample buffer: CMSampleBuffer) -> Bool {
|
||||||
|
guard isReady else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isReady = false
|
||||||
|
|
||||||
|
dataToSend = prepare(sample: buffer)
|
||||||
|
byteIndex = 0
|
||||||
|
|
||||||
|
serialQueue.async { [weak self] in
|
||||||
|
self?.sendDataChunk()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension SampleUploader {
|
||||||
|
|
||||||
|
func setupConnection() {
|
||||||
|
connection.didOpen = { [weak self] in
|
||||||
|
self?.isReady = true
|
||||||
|
}
|
||||||
|
connection.streamHasSpaceAvailable = { [weak self] in
|
||||||
|
self?.serialQueue.async {
|
||||||
|
if let success = self?.sendDataChunk() {
|
||||||
|
self?.isReady = !success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult func sendDataChunk() -> Bool {
|
||||||
|
guard let dataToSend = dataToSend else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytesLeft = dataToSend.count - byteIndex
|
||||||
|
var length = bytesLeft > Constants.bufferMaxLength ? Constants.bufferMaxLength : bytesLeft
|
||||||
|
|
||||||
|
length = dataToSend[byteIndex..<(byteIndex + length)].withUnsafeBytes {
|
||||||
|
guard let ptr = $0.bindMemory(to: UInt8.self).baseAddress else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection.writeToStream(buffer: ptr, maxLength: length)
|
||||||
|
}
|
||||||
|
|
||||||
|
if length > 0 {
|
||||||
|
byteIndex += length
|
||||||
|
bytesLeft -= length
|
||||||
|
|
||||||
|
if bytesLeft == 0 {
|
||||||
|
self.dataToSend = nil
|
||||||
|
byteIndex = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MXLog.error("writeBufferToStream failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepare(sample buffer: CMSampleBuffer) -> Data? {
|
||||||
|
guard let imageBuffer = CMSampleBufferGetImageBuffer(buffer) else {
|
||||||
|
MXLog.error("image buffer not available")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
|
||||||
|
|
||||||
|
let scaleFactor = 2.0
|
||||||
|
let width = CVPixelBufferGetWidth(imageBuffer)/Int(scaleFactor)
|
||||||
|
let height = CVPixelBufferGetHeight(imageBuffer)/Int(scaleFactor)
|
||||||
|
let orientation = CMGetAttachment(buffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil)?.uintValue ?? 0
|
||||||
|
|
||||||
|
let scaleTransform = CGAffineTransform(scaleX: CGFloat(1.0/scaleFactor), y: CGFloat(1.0/scaleFactor))
|
||||||
|
let bufferData = self.jpegData(from: imageBuffer, scale: scaleTransform)
|
||||||
|
|
||||||
|
CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly)
|
||||||
|
|
||||||
|
guard let messageData = bufferData else {
|
||||||
|
MXLog.error("corrupted image buffer")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let httpResponse = CFHTTPMessageCreateResponse(nil, 200, nil, kCFHTTPVersion1_1).takeRetainedValue()
|
||||||
|
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Content-Length" as CFString, String(messageData.count) as CFString)
|
||||||
|
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Width" as CFString, String(width) as CFString)
|
||||||
|
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Height" as CFString, String(height) as CFString)
|
||||||
|
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Orientation" as CFString, String(orientation) as CFString)
|
||||||
|
|
||||||
|
CFHTTPMessageSetBody(httpResponse, messageData as CFData)
|
||||||
|
|
||||||
|
let serializedMessage = CFHTTPMessageCopySerializedMessage(httpResponse)?.takeRetainedValue() as Data?
|
||||||
|
|
||||||
|
return serializedMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpegData(from buffer: CVPixelBuffer, scale scaleTransform: CGAffineTransform) -> Data? {
|
||||||
|
let image = CIImage(cvPixelBuffer: buffer).transformed(by: scaleTransform)
|
||||||
|
|
||||||
|
guard let colorSpace = image.colorSpace else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let options: [CIImageRepresentationOption: Float] = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0]
|
||||||
|
|
||||||
|
return SampleUploader.imageContext.jpegRepresentation(of: image, colorSpace: colorSpace, options: options)
|
||||||
|
}
|
||||||
|
}
|
203
BroadcastUploadExtension/Sources/SocketConnection.swift
Normal file
203
BroadcastUploadExtension/Sources/SocketConnection.swift
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
//
|
||||||
|
// License from the original repository:
|
||||||
|
// https://github.com/jitsi/jitsi-meet-sdk-samples/blob/master/LICENSE
|
||||||
|
//
|
||||||
|
// SocketConnection.swift
|
||||||
|
// Broadcast Extension
|
||||||
|
//
|
||||||
|
// Created by Alex-Dan Bumbu on 22/03/2021.
|
||||||
|
// Copyright © 2021 Atlassian Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
import MatrixSDK
|
||||||
|
|
||||||
|
class SocketConnection: NSObject {
|
||||||
|
var didOpen: (() -> Void)?
|
||||||
|
var didClose: ((Error?) -> Void)?
|
||||||
|
var streamHasSpaceAvailable: (() -> Void)?
|
||||||
|
|
||||||
|
private let filePath: String
|
||||||
|
private var socketHandle: Int32 = -1
|
||||||
|
private var address: sockaddr_un?
|
||||||
|
|
||||||
|
private var inputStream: InputStream?
|
||||||
|
private var outputStream: OutputStream?
|
||||||
|
|
||||||
|
private var networkQueue: DispatchQueue?
|
||||||
|
private var shouldKeepRunning = false
|
||||||
|
|
||||||
|
init?(filePath path: String) {
|
||||||
|
filePath = path
|
||||||
|
socketHandle = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
|
||||||
|
|
||||||
|
guard socketHandle != -1 else {
|
||||||
|
MXLog.error("failure: create socket")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func open() -> Bool {
|
||||||
|
MXLog.info("open socket connection")
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: filePath) else {
|
||||||
|
MXLog.error("failure: socket file missing")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
guard setupAddress() == true else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
guard connectSocket() == true else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
setupStreams()
|
||||||
|
|
||||||
|
inputStream?.open()
|
||||||
|
outputStream?.open()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func close() {
|
||||||
|
unscheduleStreams()
|
||||||
|
|
||||||
|
inputStream?.delegate = nil
|
||||||
|
outputStream?.delegate = nil
|
||||||
|
|
||||||
|
inputStream?.close()
|
||||||
|
outputStream?.close()
|
||||||
|
|
||||||
|
inputStream = nil
|
||||||
|
outputStream = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeToStream(buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int {
|
||||||
|
outputStream?.write(buffer, maxLength: length) ?? 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SocketConnection: StreamDelegate {
|
||||||
|
|
||||||
|
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||||
|
switch eventCode {
|
||||||
|
case .openCompleted:
|
||||||
|
MXLog.info("client stream open completed")
|
||||||
|
if aStream == outputStream {
|
||||||
|
didOpen?()
|
||||||
|
}
|
||||||
|
case .hasBytesAvailable:
|
||||||
|
if aStream == inputStream {
|
||||||
|
var buffer: UInt8 = 0
|
||||||
|
let numberOfBytesRead = inputStream?.read(&buffer, maxLength: 1)
|
||||||
|
if numberOfBytesRead == 0 && aStream.streamStatus == .atEnd {
|
||||||
|
MXLog.info("server socket closed")
|
||||||
|
close()
|
||||||
|
notifyDidClose(error: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .hasSpaceAvailable:
|
||||||
|
if aStream == outputStream {
|
||||||
|
streamHasSpaceAvailable?()
|
||||||
|
}
|
||||||
|
case .errorOccurred:
|
||||||
|
MXLog.error("client stream error occured", context: aStream.streamError)
|
||||||
|
close()
|
||||||
|
notifyDidClose(error: aStream.streamError)
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension SocketConnection {
|
||||||
|
|
||||||
|
func setupAddress() -> Bool {
|
||||||
|
var addr = sockaddr_un()
|
||||||
|
guard filePath.count < MemoryLayout.size(ofValue: addr.sun_path) else {
|
||||||
|
MXLog.error("failure: fd path is too long")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
|
||||||
|
filePath.withCString {
|
||||||
|
strncpy(ptr, $0, filePath.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
address = addr
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectSocket() -> Bool {
|
||||||
|
guard var addr = address else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = withUnsafePointer(to: &addr) { ptr in
|
||||||
|
ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||||
|
Darwin.connect(socketHandle, $0, socklen_t(MemoryLayout<sockaddr_un>.size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard status == noErr else {
|
||||||
|
MXLog.error("connect socket failure", context: status)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupStreams() {
|
||||||
|
var readStream: Unmanaged<CFReadStream>?
|
||||||
|
var writeStream: Unmanaged<CFWriteStream>?
|
||||||
|
|
||||||
|
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketHandle, &readStream, &writeStream)
|
||||||
|
|
||||||
|
inputStream = readStream?.takeRetainedValue()
|
||||||
|
inputStream?.delegate = self
|
||||||
|
inputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
|
||||||
|
|
||||||
|
outputStream = writeStream?.takeRetainedValue()
|
||||||
|
outputStream?.delegate = self
|
||||||
|
outputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
|
||||||
|
|
||||||
|
scheduleStreams()
|
||||||
|
}
|
||||||
|
|
||||||
|
func scheduleStreams() {
|
||||||
|
shouldKeepRunning = true
|
||||||
|
|
||||||
|
networkQueue = DispatchQueue.global(qos: .userInitiated)
|
||||||
|
networkQueue?.async { [weak self] in
|
||||||
|
self?.inputStream?.schedule(in: .current, forMode: .common)
|
||||||
|
self?.outputStream?.schedule(in: .current, forMode: .common)
|
||||||
|
RunLoop.current.run()
|
||||||
|
|
||||||
|
var isRunning = false
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
isRunning = self?.shouldKeepRunning ?? false && RunLoop.current.run(mode: .default, before: .distantFuture)
|
||||||
|
} while (isRunning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unscheduleStreams() {
|
||||||
|
networkQueue?.sync { [weak self] in
|
||||||
|
self?.inputStream?.remove(from: .current, forMode: .common)
|
||||||
|
self?.outputStream?.remove(from: .current, forMode: .common)
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldKeepRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func notifyDidClose(error: Error?) {
|
||||||
|
if didClose != nil {
|
||||||
|
didClose?(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?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>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>$(APPLICATION_GROUP_IDENTIFIER)</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
33
BroadcastUploadExtension/SupportingFiles/Info.plist
Normal file
33
BroadcastUploadExtension/SupportingFiles/Info.plist
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?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>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XPC!</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>$(BUNDLE_DISPLAY_NAME)</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.broadcast-services-upload</string>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).SampleHandler</string>
|
||||||
|
<key>RPBroadcastProcessMode</key>
|
||||||
|
<string>RPBroadcastProcessModeSampleBuffer</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
42
BroadcastUploadExtension/target.yml
Normal file
42
BroadcastUploadExtension/target.yml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
name: BroadcastUploadExtension
|
||||||
|
|
||||||
|
schemes:
|
||||||
|
BroadcastUploadExtension:
|
||||||
|
analyze:
|
||||||
|
config: Debug
|
||||||
|
archive:
|
||||||
|
config: Release
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
BroadcastUploadExtension:
|
||||||
|
- running
|
||||||
|
- testing
|
||||||
|
- profiling
|
||||||
|
- analyzing
|
||||||
|
- archiving
|
||||||
|
profile:
|
||||||
|
config: Release
|
||||||
|
run:
|
||||||
|
askForAppToLaunch: true
|
||||||
|
config: Debug
|
||||||
|
debugEnabled: false
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
launchAutomaticallySubstyle: 2
|
||||||
|
test:
|
||||||
|
config: Debug
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
|
||||||
|
targets:
|
||||||
|
BroadcastUploadExtension:
|
||||||
|
platform: iOS
|
||||||
|
type: app-extension
|
||||||
|
|
||||||
|
configFiles:
|
||||||
|
Debug: Debug.xcconfig
|
||||||
|
Release: Release.xcconfig
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- path: .
|
||||||
|
- path: ../Config/BuildSettings.swift
|
||||||
|
- path: ../Riot/Categories/Bundle.swift
|
||||||
|
- path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift
|
|
@ -37,3 +37,6 @@ SHARE_EXTENSION_PROVISIONING_PROFILE = 8c797ca0-0440-49bd-be8d-11d761152995
|
||||||
|
|
||||||
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Vector Siri Intents: App Store"
|
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Vector Siri Intents: App Store"
|
||||||
SIRI_INTENTS_PROVISIONING_PROFILE = 1690e81a-5ad3-4d99-b578-02693579be71
|
SIRI_INTENTS_PROVISIONING_PROFILE = 1690e81a-5ad3-4d99-b578-02693579be71
|
||||||
|
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER = "Vector Broadcast Upload Extension: App Store"
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE = c86239f4-0d3a-47f4-a5f2-9f4763c42b5d
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
// Application constants
|
// Application constants
|
||||||
KEYCHAIN_ACCESS_GROUP = $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER).keychain.shared
|
KEYCHAIN_ACCESS_GROUP = $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER).keychain.shared
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).broadcastUploadExtension
|
||||||
|
|
||||||
// Build settings
|
// Build settings
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0
|
||||||
|
|
4
Podfile
4
Podfile
|
@ -127,6 +127,10 @@ abstract_target 'RiotPods' do
|
||||||
import_MatrixKit_pods
|
import_MatrixKit_pods
|
||||||
end
|
end
|
||||||
|
|
||||||
|
target "BroadcastUploadExtension" do
|
||||||
|
import_MatrixSDK
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
|
|
|
@ -35,6 +35,7 @@ static NSString * _Nonnull kRCTTextViewClassName = @"RCTTextView";
|
||||||
Some feature flags defined in https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
|
Some feature flags defined in https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
|
||||||
*/
|
*/
|
||||||
static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
||||||
|
static NSString * _Nonnull kJitsiFeatureFlagScreenSharingEnabled = @"ios.screensharing.enabled";
|
||||||
|
|
||||||
@interface JitsiViewController () <PictureInPicturable, JitsiMeetViewDelegate>
|
@interface JitsiViewController () <PictureInPicturable, JitsiMeetViewDelegate>
|
||||||
|
|
||||||
|
@ -278,6 +279,7 @@ static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
||||||
andAvatar:avatarUrl];
|
andAvatar:avatarUrl];
|
||||||
builder.token = self.jwtToken;
|
builder.token = self.jwtToken;
|
||||||
[builder setFeatureFlag:kJitsiFeatureFlagChatEnabled withBoolean:NO];
|
[builder setFeatureFlag:kJitsiFeatureFlagChatEnabled withBoolean:NO];
|
||||||
|
[builder setFeatureFlag:kJitsiFeatureFlagScreenSharingEnabled withBoolean: YES];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self.jitsiMeetView join:jitsiMeetConferenceOptions];
|
[self.jitsiMeetView join:jitsiMeetConferenceOptions];
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
|
<key>RTCAppGroupIdentifier</key>
|
||||||
|
<string>$(APPLICATION_GROUP_IDENTIFIER)</string>
|
||||||
|
<key>RTCScreenSharingExtension</key>
|
||||||
|
<string>$(BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>$(BUNDLE_DISPLAY_NAME)</string>
|
<string>$(BUNDLE_DISPLAY_NAME)</string>
|
||||||
<key>CFBundleDocumentTypes</key>
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
|
|
@ -37,6 +37,7 @@ targets:
|
||||||
- target: RiotShareExtension
|
- target: RiotShareExtension
|
||||||
- target: SiriIntents
|
- target: SiriIntents
|
||||||
- target: RiotNSE
|
- target: RiotNSE
|
||||||
|
- target: BroadcastUploadExtension
|
||||||
- target: DesignKit
|
- target: DesignKit
|
||||||
- target: CommonKit
|
- target: CommonKit
|
||||||
- package: AnalyticsEvents
|
- package: AnalyticsEvents
|
||||||
|
|
|
@ -38,3 +38,6 @@ SHARE_EXTENSION_PROVISIONING_PROFILE = b47f96e0-647b-4274-b2bb-8103b9a97146
|
||||||
|
|
||||||
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Alpha Vector Siri Intents Ad hoc"
|
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Alpha Vector Siri Intents Ad hoc"
|
||||||
SIRI_INTENTS_PROVISIONING_PROFILE = a9fdb684-a68c-4207-afc2-810f3287b1f5
|
SIRI_INTENTS_PROVISIONING_PROFILE = a9fdb684-a68c-4207-afc2-810f3287b1f5
|
||||||
|
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER = "Alpha Vector Broadcast Upload Extension Ad hoc"
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE = 3616761e-f7f6-4f38-bf74-13bc6b0a1000
|
||||||
|
|
|
@ -7,11 +7,13 @@ MAIN_TARGET=Riot
|
||||||
SHARE_EXTENSION_TARGET=RiotShareExtension
|
SHARE_EXTENSION_TARGET=RiotShareExtension
|
||||||
SIRI_INTENTS_EXTENSION_TARGET=SiriIntents
|
SIRI_INTENTS_EXTENSION_TARGET=SiriIntents
|
||||||
NSE_TARGET=RiotNSE
|
NSE_TARGET=RiotNSE
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_TARGET=BroadcastUploadExtension
|
||||||
|
|
||||||
MAIN_BUNDLE_ID=im.vector.app.alpha
|
MAIN_BUNDLE_ID=im.vector.app.alpha
|
||||||
SHARE_EXTENSION_BUNDLE_ID=im.vector.app.alpha.shareExtension
|
SHARE_EXTENSION_BUNDLE_ID=im.vector.app.alpha.shareExtension
|
||||||
SIRI_INTENTS_EXTENSION_BUNDLE_ID=im.vector.app.alpha.SiriIntents
|
SIRI_INTENTS_EXTENSION_BUNDLE_ID=im.vector.app.alpha.SiriIntents
|
||||||
NSE_BUNDLE_ID=im.vector.app.alpha.nse
|
NSE_BUNDLE_ID=im.vector.app.alpha.nse
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_BUNDLE_ID=im.vector.app.alpha.broadcastUploadExtension
|
||||||
|
|
||||||
## Build configuration
|
## Build configuration
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ MAIN_PROVISIONING_PROFILE_FILENAME=main.mobileprovision
|
||||||
SHARE_EXTENSION_PROVISIONING_PROFILE_FILENAME=share_extension.mobileprovision
|
SHARE_EXTENSION_PROVISIONING_PROFILE_FILENAME=share_extension.mobileprovision
|
||||||
SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_FILENAME=siri_intents.mobileprovision
|
SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_FILENAME=siri_intents.mobileprovision
|
||||||
NSE_PROVISIONING_PROFILE_FILENAME=nse.mobileprovision
|
NSE_PROVISIONING_PROFILE_FILENAME=nse.mobileprovision
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_FILENAME=broadcast_upload_extension.mobileprovision
|
||||||
|
|
||||||
## App Store code signing
|
## App Store code signing
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ APPSTORE_MAIN_PROVISIONING_PROFILE_SPECIFIER="Vector App Store"
|
||||||
APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: App Store"
|
APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: App Store"
|
||||||
APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: App Store"
|
APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: App Store"
|
||||||
APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: App Store"
|
APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: App Store"
|
||||||
|
APPSTORE_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Broadcast Upload Extension: App Store"
|
||||||
|
|
||||||
## Ad-Hoc code signing
|
## Ad-Hoc code signing
|
||||||
|
|
||||||
|
@ -46,6 +50,7 @@ ADHOC_MAIN_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector App Ad hoc"
|
||||||
ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector Share Extension Ad hoc"
|
ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector Share Extension Ad hoc"
|
||||||
ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector Siri Intents Ad hoc"
|
ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector Siri Intents Ad hoc"
|
||||||
ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector NSE Ad hoc"
|
ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector NSE Ad hoc"
|
||||||
|
ADHOC_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Alpha Vector Broadcast Upload Extension Ad hoc"
|
||||||
|
|
||||||
## Account information
|
## Account information
|
||||||
|
|
||||||
|
|
1
changelog.d/7566.feature
Normal file
1
changelog.d/7566.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Broadcast Upload Extension added to the app targets to allow Jitsi screen sharing feature.
|
|
@ -7,11 +7,13 @@ MAIN_TARGET=Riot
|
||||||
SHARE_EXTENSION_TARGET=RiotShareExtension
|
SHARE_EXTENSION_TARGET=RiotShareExtension
|
||||||
SIRI_INTENTS_EXTENSION_TARGET=SiriIntents
|
SIRI_INTENTS_EXTENSION_TARGET=SiriIntents
|
||||||
NSE_TARGET=RiotNSE
|
NSE_TARGET=RiotNSE
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_TARGET=BroadcastUploadExtension
|
||||||
|
|
||||||
MAIN_BUNDLE_ID=im.vector.app
|
MAIN_BUNDLE_ID=im.vector.app
|
||||||
SHARE_EXTENSION_BUNDLE_ID=im.vector.app.shareExtension
|
SHARE_EXTENSION_BUNDLE_ID=im.vector.app.shareExtension
|
||||||
SIRI_INTENTS_EXTENSION_BUNDLE_ID=im.vector.app.SiriIntents
|
SIRI_INTENTS_EXTENSION_BUNDLE_ID=im.vector.app.SiriIntents
|
||||||
NSE_BUNDLE_ID=im.vector.app.nse
|
NSE_BUNDLE_ID=im.vector.app.nse
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_BUNDLE_ID=im.vector.app.broadcastUploadExtension
|
||||||
|
|
||||||
## Build configuration
|
## Build configuration
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ MAIN_PROVISIONING_PROFILE_FILENAME=main.mobileprovision
|
||||||
SHARE_EXTENSION_PROVISIONING_PROFILE_FILENAME=share_extension.mobileprovision
|
SHARE_EXTENSION_PROVISIONING_PROFILE_FILENAME=share_extension.mobileprovision
|
||||||
SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_FILENAME=siri_intents.mobileprovision
|
SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_FILENAME=siri_intents.mobileprovision
|
||||||
NSE_PROVISIONING_PROFILE_FILENAME=nse.mobileprovision
|
NSE_PROVISIONING_PROFILE_FILENAME=nse.mobileprovision
|
||||||
|
BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_FILENAME=broadcast_upload_extension.mobileprovision
|
||||||
|
|
||||||
## App Store code signing
|
## App Store code signing
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ APPSTORE_MAIN_PROVISIONING_PROFILE_SPECIFIER="Vector App Store"
|
||||||
APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: App Store"
|
APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: App Store"
|
||||||
APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: App Store"
|
APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: App Store"
|
||||||
APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: App Store"
|
APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: App Store"
|
||||||
|
APPSTORE_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Broadcast Upload Extension: App Store"
|
||||||
|
|
||||||
## Ad-Hoc code signing
|
## Ad-Hoc code signing
|
||||||
|
|
||||||
|
@ -46,6 +50,7 @@ ADHOC_MAIN_PROVISIONING_PROFILE_SPECIFIER="Vector Ad Hoc"
|
||||||
ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: Ad Hoc"
|
ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Share Extension: Ad Hoc"
|
||||||
ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: Ad Hoc"
|
ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Siri Intents: Ad Hoc"
|
||||||
ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: Ad Hoc"
|
ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER="Vector NSE: Ad Hoc"
|
||||||
|
ADHOC_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER="Vector Broadcast Upload Extension: Ad Hoc"
|
||||||
|
|
||||||
## Account information
|
## Account information
|
||||||
|
|
||||||
|
|
|
@ -290,12 +290,14 @@ platform :ios do
|
||||||
share_extension_provisioning_profile = ENV["ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
share_extension_provisioning_profile = ENV["ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
siri_intents_provisioning_profile = ENV["ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
siri_intents_provisioning_profile = ENV["ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
nse_provisioning_profile = ENV["ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
nse_provisioning_profile = ENV["ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
|
broadcast_upload_extension_provisioning_profile = ENV["ADHOC_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
else
|
else
|
||||||
export_method = "app-store"
|
export_method = "app-store"
|
||||||
main_provisioning_profile = ENV["APPSTORE_MAIN_PROVISIONING_PROFILE_SPECIFIER"]
|
main_provisioning_profile = ENV["APPSTORE_MAIN_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
share_extension_provisioning_profile = ENV["APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
share_extension_provisioning_profile = ENV["APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
siri_intents_provisioning_profile = ENV["APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
siri_intents_provisioning_profile = ENV["APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
nse_provisioning_profile = ENV["APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
nse_provisioning_profile = ENV["APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
|
broadcast_upload_extension_provisioning_profile = ENV["APPSTORE_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Build app and create ipa
|
# Build app and create ipa
|
||||||
|
@ -321,6 +323,7 @@ platform :ios do
|
||||||
ENV["SHARE_EXTENSION_BUNDLE_ID"] => share_extension_provisioning_profile,
|
ENV["SHARE_EXTENSION_BUNDLE_ID"] => share_extension_provisioning_profile,
|
||||||
ENV["NSE_BUNDLE_ID"] => nse_provisioning_profile,
|
ENV["NSE_BUNDLE_ID"] => nse_provisioning_profile,
|
||||||
ENV["SIRI_INTENTS_EXTENSION_BUNDLE_ID"] => siri_intents_provisioning_profile,
|
ENV["SIRI_INTENTS_EXTENSION_BUNDLE_ID"] => siri_intents_provisioning_profile,
|
||||||
|
ENV["BROADCAST_UPLOAD_EXTENSION_BUNDLE_ID"] => broadcast_upload_extension_provisioning_profile,
|
||||||
},
|
},
|
||||||
iCloudContainerEnvironment: "Production",
|
iCloudContainerEnvironment: "Production",
|
||||||
},
|
},
|
||||||
|
@ -340,6 +343,7 @@ platform :ios do
|
||||||
share_extension_provisioning_name = adhoc ? ENV["ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
share_extension_provisioning_name = adhoc ? ENV["ADHOC_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
siri_intents_provisioning_name = adhoc ? ENV["ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
siri_intents_provisioning_name = adhoc ? ENV["ADHOC_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_SIRI_INTENTS_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
notification_service_extension_provisioning_name = adhoc ? ENV["ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
notification_service_extension_provisioning_name = adhoc ? ENV["ADHOC_NSE_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_NSE_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
|
broadcast_upload_extension_provisioning_name = adhoc ? ENV["ADHOC_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"] : ENV["APPSTORE_BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_SPECIFIER"]
|
||||||
|
|
||||||
# Main application
|
# Main application
|
||||||
get_provisioning_profile(
|
get_provisioning_profile(
|
||||||
|
@ -385,6 +389,17 @@ platform :ios do
|
||||||
filename: ENV["NSE_PROVISIONING_PROFILE_FILENAME"],
|
filename: ENV["NSE_PROVISIONING_PROFILE_FILENAME"],
|
||||||
readonly: true,
|
readonly: true,
|
||||||
)
|
)
|
||||||
|
# Broadcast Upload Extension
|
||||||
|
get_provisioning_profile(
|
||||||
|
app_identifier: ENV["BROADCAST_UPLOAD_EXTENSION_BUNDLE_ID"],
|
||||||
|
provisioning_name: broadcast_upload_extension_provisioning_name,
|
||||||
|
ignore_profiles_with_different_name: true,
|
||||||
|
adhoc: adhoc,
|
||||||
|
skip_certificate_verification: skip_certificate_verification,
|
||||||
|
output_path: output_path,
|
||||||
|
filename: ENV["BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_FILENAME"],
|
||||||
|
readonly: true,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Update provisioning profiles for each target"
|
desc "Update provisioning profiles for each target"
|
||||||
|
@ -421,6 +436,13 @@ platform :ios do
|
||||||
target_filter: ENV["NSE_TARGET"],
|
target_filter: ENV["NSE_TARGET"],
|
||||||
build_configuration: build_configuration,
|
build_configuration: build_configuration,
|
||||||
)
|
)
|
||||||
|
# Broadcast Upload Extension
|
||||||
|
update_project_provisioning(
|
||||||
|
xcodeproj: xcodeproj,
|
||||||
|
profile: "#{provisioning_profiles_path}#{ENV["BROADCAST_UPLOAD_EXTENSION_PROVISIONING_PROFILE_FILENAME"]}",
|
||||||
|
target_filter: ENV["BROADCAST_UPLOAD_EXTENSION_TARGET"],
|
||||||
|
build_configuration: build_configuration,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Update application build number for all targets"
|
desc "Update application build number for all targets"
|
||||||
|
|
|
@ -32,6 +32,7 @@ include:
|
||||||
- path: RiotShareExtension/target.yml
|
- path: RiotShareExtension/target.yml
|
||||||
- path: SiriIntents/target.yml
|
- path: SiriIntents/target.yml
|
||||||
- path: RiotNSE/target.yml
|
- path: RiotNSE/target.yml
|
||||||
|
- path: BroadcastUploadExtension/target.yml
|
||||||
- path: DesignKit/target.yml
|
- path: DesignKit/target.yml
|
||||||
- path: RiotSwiftUI/target.yml
|
- path: RiotSwiftUI/target.yml
|
||||||
- path: RiotSwiftUI/targetUnitTests.yml
|
- path: RiotSwiftUI/targetUnitTests.yml
|
||||||
|
|
Loading…
Reference in a new issue