mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 11:48:27 +00:00
Handle VoIP and APNs push received before shared filesystem is available (BFU)
Delay CoreContext initialization until AppServices.config is available.
When a VoIP push arrives before that, an EarlyPushkitDelegate reports
a temporary CallKit call, ends it as unanswered after 4s, and posts
a missed call notification to the user.
Handle message APNs in service extension without Core/Config availability
This commit is contained in:
parent
0132c5253f
commit
156231f8aa
8 changed files with 195 additions and 34 deletions
|
|
@ -566,15 +566,30 @@ class CoreContext: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppServices {
|
enum AppServices {
|
||||||
static let config = Config.newForSharedCore(
|
private static var _config: Config?
|
||||||
appGroupId: Bundle.main.object(forInfoDictionaryKey: "APP_GROUP_NAME") as? String
|
|
||||||
?? {
|
static var configIfAvailable: Config? {
|
||||||
fatalError("APP_GROUP_NAME not defined in Info.plist")
|
if let existing = _config {
|
||||||
}(),
|
return existing
|
||||||
configFilename: "linphonerc",
|
}
|
||||||
factoryConfigFilename: FileUtil.bundleFilePath("linphonerc-factory")
|
_config = Config.newForSharedCore(
|
||||||
)!
|
appGroupId: Bundle.main.object(forInfoDictionaryKey: "APP_GROUP_NAME") as? String
|
||||||
|
?? {
|
||||||
|
fatalError("APP_GROUP_NAME not defined in Info.plist")
|
||||||
|
}(),
|
||||||
|
configFilename: "linphonerc",
|
||||||
|
factoryConfigFilename: FileUtil.bundleFilePath("linphonerc-factory")
|
||||||
|
)
|
||||||
|
return _config
|
||||||
|
}
|
||||||
|
|
||||||
|
static var config: Config {
|
||||||
|
guard let config = configIfAvailable else {
|
||||||
|
fatalError("AppServices.config accessed before it was available")
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
static let corePreferences = CorePreferences(config: config)
|
static let corePreferences = CorePreferences(config: config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import SwiftUI
|
||||||
import linphonesw
|
import linphonesw
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
import Intents
|
import Intents
|
||||||
|
import PushKit
|
||||||
|
|
||||||
let accountTokenNotification = Notification.Name("AccountCreationTokenReceived")
|
let accountTokenNotification = Notification.Name("AccountCreationTokenReceived")
|
||||||
var displayedChatroomPeerAddr: String?
|
var displayedChatroomPeerAddr: String?
|
||||||
|
|
@ -151,28 +152,69 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct LinphoneApp: App {
|
struct LinphoneApp: App {
|
||||||
@Environment(\.scenePhase) var scenePhase
|
|
||||||
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
|
||||||
|
|
||||||
|
@State private var configAvailable = AppServices.configIfAvailable != nil
|
||||||
|
private let earlyPushDelegate = EarlyPushkitDelegate()
|
||||||
|
private let voipRegistry = PKPushRegistry(queue: coreQueue)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
if !configAvailable {
|
||||||
|
voipRegistry.delegate = earlyPushDelegate
|
||||||
|
voipRegistry.desiredPushTypes = [.voIP]
|
||||||
|
waitForConfig()
|
||||||
|
} else {
|
||||||
|
let _ = CoreContext.shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some Scene {
|
||||||
|
WindowGroup {
|
||||||
|
if configAvailable {
|
||||||
|
AppView(delegate: delegate)
|
||||||
|
} else {
|
||||||
|
SplashScreen(showSpinner: true)
|
||||||
|
.onAppear {
|
||||||
|
waitForConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func waitForConfig() {
|
||||||
|
if AppServices.configIfAvailable != nil {
|
||||||
|
let _ = CoreContext.shared
|
||||||
|
configAvailable = true
|
||||||
|
} else {
|
||||||
|
Log.warn("AppServices.config not available yet, retrying in 1s...")
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
|
waitForConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppView: View {
|
||||||
|
@Environment(\.scenePhase) var scenePhase
|
||||||
|
let delegate: AppDelegate
|
||||||
|
|
||||||
@StateObject private var coreContext = CoreContext.shared
|
@StateObject private var coreContext = CoreContext.shared
|
||||||
@StateObject private var navigationManager = NavigationManager()
|
@StateObject private var navigationManager = NavigationManager()
|
||||||
@StateObject private var telecomManager = TelecomManager.shared
|
@StateObject private var telecomManager = TelecomManager.shared
|
||||||
@StateObject private var sharedMainViewModel = SharedMainViewModel.shared
|
@StateObject private var sharedMainViewModel = SharedMainViewModel.shared
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some View {
|
||||||
WindowGroup {
|
RootView(
|
||||||
RootView(
|
coreContext: coreContext,
|
||||||
coreContext: coreContext,
|
telecomManager: telecomManager,
|
||||||
telecomManager: telecomManager,
|
sharedMainViewModel: sharedMainViewModel,
|
||||||
sharedMainViewModel: sharedMainViewModel,
|
navigationManager: navigationManager,
|
||||||
navigationManager: navigationManager,
|
appDelegate: delegate
|
||||||
appDelegate: delegate
|
)
|
||||||
)
|
.environmentObject(coreContext)
|
||||||
.environmentObject(coreContext)
|
.environmentObject(navigationManager)
|
||||||
.environmentObject(navigationManager)
|
.environmentObject(telecomManager)
|
||||||
.environmentObject(telecomManager)
|
.environmentObject(sharedMainViewModel)
|
||||||
.environmentObject(sharedMainViewModel)
|
|
||||||
}
|
|
||||||
.onChange(of: scenePhase) { newPhase in
|
.onChange(of: scenePhase) { newPhase in
|
||||||
if !telecomManager.callInProgress {
|
if !telecomManager.callInProgress {
|
||||||
switch newPhase {
|
switch newPhase {
|
||||||
|
|
|
||||||
|
|
@ -616,3 +616,6 @@
|
||||||
"welcome_page_title" = "Welcome";
|
"welcome_page_title" = "Welcome";
|
||||||
"You will change this mode later" = "You will change this mode later";
|
"You will change this mode later" = "You will change this mode later";
|
||||||
"ZRTP" = "ZRTP";
|
"ZRTP" = "ZRTP";
|
||||||
|
"early_push_unknown_caller" = "Unknown";
|
||||||
|
"early_push_missed_call_title" = "Missed call";
|
||||||
|
"early_push_missed_call_body" = "You received a call while your device was locked. Please unlock and reopen the app.";
|
||||||
|
|
|
||||||
|
|
@ -616,3 +616,6 @@
|
||||||
"welcome_page_title" = "Bienvenue";
|
"welcome_page_title" = "Bienvenue";
|
||||||
"You will change this mode later" = "You will change this mode later";
|
"You will change this mode later" = "You will change this mode later";
|
||||||
"ZRTP" = "ZRTP";
|
"ZRTP" = "ZRTP";
|
||||||
|
"early_push_unknown_caller" = "Inconnu";
|
||||||
|
"early_push_missed_call_title" = "Appel manqué";
|
||||||
|
"early_push_missed_call_body" = "Vous avez reçu un appel alors que votre appareil était verrouillé. Veuillez déverrouiller et rouvrir l'application.";
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,23 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SplashScreen: View {
|
struct SplashScreen: View {
|
||||||
|
var showSpinner: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.white
|
Color.white
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
Image("linphone")
|
Image("linphone")
|
||||||
.resizable()
|
.resizable()
|
||||||
.renderingMode(.template)
|
.renderingMode(.template)
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: 240, height: 128)
|
.frame(width: 240, height: 128)
|
||||||
.foregroundColor(ThemeManager.shared.currentTheme.main500)
|
.foregroundColor(ThemeManager.shared.currentTheme.main500)
|
||||||
|
|
||||||
|
if showSpinner {
|
||||||
|
ProgressView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
|
|
|
||||||
81
Linphone/TelecomManager/EarlyPushkitDelegate.swift
Normal file
81
Linphone/TelecomManager/EarlyPushkitDelegate.swift
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PushKit
|
||||||
|
import CallKit
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
|
class EarlyPushkitDelegate: NSObject, PKPushRegistryDelegate, CXProviderDelegate {
|
||||||
|
private var activeCalls: [UUID: CXProvider] = [:]
|
||||||
|
|
||||||
|
func providerDidReset(_ provider: CXProvider) {}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
||||||
|
Log.info("[EarlyPushkitDelegate] User tried to answer, ending call as device is locked")
|
||||||
|
action.fail()
|
||||||
|
provider.reportCall(with: action.callUUID, endedAt: .init(), reason: .unanswered)
|
||||||
|
activeCalls.removeValue(forKey: action.callUUID)
|
||||||
|
postMissedCallNotification()
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
|
||||||
|
Log.info("[EarlyPushkitDelegate] Received push credentials, ignoring until core is ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
|
||||||
|
Log.info("[EarlyPushkitDelegate] Received incoming push while core is not ready, reporting call to CallKit")
|
||||||
|
let providerConfig = CXProviderConfiguration()
|
||||||
|
providerConfig.supportsVideo = false
|
||||||
|
let provider = CXProvider(configuration: providerConfig)
|
||||||
|
provider.setDelegate(self, queue: .main)
|
||||||
|
|
||||||
|
let update = CXCallUpdate()
|
||||||
|
update.remoteHandle = CXHandle(type: .generic, value: NSLocalizedString("early_push_unknown_caller", comment: ""))
|
||||||
|
update.hasVideo = false
|
||||||
|
let uuid = UUID()
|
||||||
|
activeCalls[uuid] = provider
|
||||||
|
|
||||||
|
provider.reportNewIncomingCall(with: uuid, update: update) { error in
|
||||||
|
if let error = error {
|
||||||
|
Log.error("[EarlyPushkitDelegate] Failed to report call to CallKit: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 4) { [weak self] in
|
||||||
|
guard let self = self, let provider = self.activeCalls.removeValue(forKey: uuid) else { return }
|
||||||
|
Log.info("[EarlyPushkitDelegate] Ending unanswered call after timeout")
|
||||||
|
provider.reportCall(with: uuid, endedAt: .init(), reason: .unanswered)
|
||||||
|
self.postMissedCallNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func postMissedCallNotification() {
|
||||||
|
let content = UNMutableNotificationContent()
|
||||||
|
content.title = NSLocalizedString("early_push_missed_call_title", comment: "")
|
||||||
|
content.body = NSLocalizedString("early_push_missed_call_body", comment: "")
|
||||||
|
content.sound = .default
|
||||||
|
let request = UNNotificationRequest(identifier: "early_push_missed_call", content: content, trigger: nil)
|
||||||
|
UNUserNotificationCenter.current().add(request) { error in
|
||||||
|
if let error = error {
|
||||||
|
Log.error("[EarlyPushkitDelegate] Failed to post missed call notification: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
C642277B2E8E4AC50094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
C642277B2E8E4AC50094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
||||||
C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
C642277C2E8E4D900094FEDC /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C642277A2E8E4AC50094FEDC /* ThemeManager.swift */; };
|
||||||
C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
|
C642277D2E8E4E2B0094FEDC /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
|
||||||
|
C65270F82F879D2700FF248C /* EarlyPushkitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */; };
|
||||||
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; };
|
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; };
|
||||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
||||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
||||||
|
|
@ -307,6 +308,7 @@
|
||||||
C62817312C1C400A00DBA646 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
|
C62817312C1C400A00DBA646 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
|
||||||
C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = "<group>"; };
|
||||||
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
C642277A2E8E4AC50094FEDC /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
||||||
|
C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarlyPushkitDelegate.swift; sourceTree = "<group>"; };
|
||||||
C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
|
C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
|
||||||
C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = "<group>"; };
|
C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = "<group>"; };
|
||||||
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = "<group>"; };
|
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -593,6 +595,7 @@
|
||||||
662B69D72B25DDF6007118BF /* TelecomManager */ = {
|
662B69D72B25DDF6007118BF /* TelecomManager */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C65270F72F879D2700FF248C /* EarlyPushkitDelegate.swift */,
|
||||||
662B69D82B25DE18007118BF /* TelecomManager.swift */,
|
662B69D82B25DE18007118BF /* TelecomManager.swift */,
|
||||||
662B69DA2B25DE25007118BF /* ProviderDelegate.swift */,
|
662B69DA2B25DE25007118BF /* ProviderDelegate.swift */,
|
||||||
);
|
);
|
||||||
|
|
@ -1525,6 +1528,7 @@
|
||||||
D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */,
|
D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */,
|
||||||
D7AEB9742F324A6F00298546 /* ConversationDocumentsListFragment.swift in Sources */,
|
D7AEB9742F324A6F00298546 /* ConversationDocumentsListFragment.swift in Sources */,
|
||||||
D732A9132B04C7A300DB42BA /* HistoryListFragment.swift in Sources */,
|
D732A9132B04C7A300DB42BA /* HistoryListFragment.swift in Sources */,
|
||||||
|
C65270F82F879D2700FF248C /* EarlyPushkitDelegate.swift in Sources */,
|
||||||
D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */,
|
D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */,
|
||||||
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
||||||
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,11 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createCore()
|
if !createCore() {
|
||||||
|
bestAttemptContent.title = String(localized: "notification_chat_message_received_title")
|
||||||
|
contentHandler(bestAttemptContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
if !lc!.config!.getBool(section: "app", key: "disable_chat_feature", defaultValue: false) {
|
if !lc!.config!.getBool(section: "app", key: "disable_chat_feature", defaultValue: false) {
|
||||||
Log.info("received push payload : \(bestAttemptContent.userInfo.debugDescription)")
|
Log.info("received push payload : \(bestAttemptContent.userInfo.debugDescription)")
|
||||||
|
|
||||||
|
|
@ -314,14 +318,17 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
return msgData
|
return msgData
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCore() {
|
func createCore() -> Bool {
|
||||||
Log.info("[msgNotificationService] create core")
|
Log.info("[msgNotificationService] create core")
|
||||||
|
|
||||||
let factoryPath = FileUtil.bundleFilePath("linphonerc-factory")!
|
let factoryPath = FileUtil.bundleFilePath("linphonerc-factory")!
|
||||||
let config = Config.newForSharedCore(appGroupId: appGroupName, configFilename: "linphonerc", factoryConfigFilename: factoryPath)!
|
if let config = Config.newForSharedCore(appGroupId: appGroupName, configFilename: "linphonerc", factoryConfigFilename: factoryPath) {
|
||||||
|
lc = try? Factory.Instance.createSharedCoreWithConfig(config: config, systemContext: nil, appGroupId: appGroupName, mainCore: false)
|
||||||
lc = try? Factory.Instance.createSharedCoreWithConfig(config: config, systemContext: nil, appGroupId: appGroupName, mainCore: false)
|
return lc != nil
|
||||||
}
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func stopCore() {
|
func stopCore() {
|
||||||
Log.info("stop core")
|
Log.info("stop core")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue