Add swift tutorials for basic call, voip push and chat features with SDK 5.0

This commit is contained in:
QuentinArguillere
2020-07-24 15:55:28 +02:00
committed by QuentinArguillere
parent 22df57e83d
commit 4a5d86e9aa
107 changed files with 6976 additions and 170 deletions

View File

@@ -0,0 +1,431 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
577005D03F6821591475FBF9 /* Pods_CallKitTutorial.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 454830E9C41DBBF20AF2BD05 /* Pods_CallKitTutorial.framework */; };
6608A96624E197D5006E6C68 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608A96524E197D5006E6C68 /* AppDelegate.swift */; };
6608A96824E197D5006E6C68 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608A96724E197D5006E6C68 /* SceneDelegate.swift */; };
6608A96A24E197D5006E6C68 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608A96924E197D5006E6C68 /* ContentView.swift */; };
6608A96C24E197D5006E6C68 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6608A96B24E197D5006E6C68 /* Assets.xcassets */; };
6608A96F24E197D5006E6C68 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6608A96E24E197D5006E6C68 /* Preview Assets.xcassets */; };
6608A97224E197D5006E6C68 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6608A97024E197D5006E6C68 /* LaunchScreen.storyboard */; };
6608A97A24E19817006E6C68 /* CallKitTutorial.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608A97924E19817006E6C68 /* CallKitTutorial.swift */; };
6608A97C24E1981E006E6C68 /* CallKitProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608A97B24E1981E006E6C68 /* CallKitProviderDelegate.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
018936DA8FE1500B9E181610 /* Pods-CallKitTutorial.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallKitTutorial.debug.xcconfig"; path = "Target Support Files/Pods-CallKitTutorial/Pods-CallKitTutorial.debug.xcconfig"; sourceTree = "<group>"; };
454830E9C41DBBF20AF2BD05 /* Pods_CallKitTutorial.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CallKitTutorial.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6608A96224E197D5006E6C68 /* CallKitTutorial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CallKitTutorial.app; sourceTree = BUILT_PRODUCTS_DIR; };
6608A96524E197D5006E6C68 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
6608A96724E197D5006E6C68 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
6608A96924E197D5006E6C68 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
6608A96B24E197D5006E6C68 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6608A96E24E197D5006E6C68 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
6608A97124E197D5006E6C68 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
6608A97324E197D5006E6C68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6608A97924E19817006E6C68 /* CallKitTutorial.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitTutorial.swift; sourceTree = "<group>"; };
6608A97B24E1981E006E6C68 /* CallKitProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitProviderDelegate.swift; sourceTree = "<group>"; };
6608A97D24E19852006E6C68 /* CallKitTutorial.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CallKitTutorial.entitlements; sourceTree = "<group>"; };
C87B170DFD4D3072825B25EF /* Pods-CallKitTutorial.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallKitTutorial.release.xcconfig"; path = "Target Support Files/Pods-CallKitTutorial/Pods-CallKitTutorial.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
6608A95F24E197D5006E6C68 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
577005D03F6821591475FBF9 /* Pods_CallKitTutorial.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
319770E3ECD19EBD7557F82B /* Frameworks */ = {
isa = PBXGroup;
children = (
454830E9C41DBBF20AF2BD05 /* Pods_CallKitTutorial.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
38284A71627D413A7ACC2F07 /* Pods */ = {
isa = PBXGroup;
children = (
018936DA8FE1500B9E181610 /* Pods-CallKitTutorial.debug.xcconfig */,
C87B170DFD4D3072825B25EF /* Pods-CallKitTutorial.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
6608A95924E197D5006E6C68 = {
isa = PBXGroup;
children = (
6608A96424E197D5006E6C68 /* CallKitTutorial */,
6608A96324E197D5006E6C68 /* Products */,
38284A71627D413A7ACC2F07 /* Pods */,
319770E3ECD19EBD7557F82B /* Frameworks */,
);
sourceTree = "<group>";
};
6608A96324E197D5006E6C68 /* Products */ = {
isa = PBXGroup;
children = (
6608A96224E197D5006E6C68 /* CallKitTutorial.app */,
);
name = Products;
sourceTree = "<group>";
};
6608A96424E197D5006E6C68 /* CallKitTutorial */ = {
isa = PBXGroup;
children = (
6608A97D24E19852006E6C68 /* CallKitTutorial.entitlements */,
6608A96524E197D5006E6C68 /* AppDelegate.swift */,
6608A96724E197D5006E6C68 /* SceneDelegate.swift */,
6608A97B24E1981E006E6C68 /* CallKitProviderDelegate.swift */,
6608A97924E19817006E6C68 /* CallKitTutorial.swift */,
6608A96924E197D5006E6C68 /* ContentView.swift */,
6608A96B24E197D5006E6C68 /* Assets.xcassets */,
6608A97024E197D5006E6C68 /* LaunchScreen.storyboard */,
6608A97324E197D5006E6C68 /* Info.plist */,
6608A96D24E197D5006E6C68 /* Preview Content */,
);
path = CallKitTutorial;
sourceTree = "<group>";
};
6608A96D24E197D5006E6C68 /* Preview Content */ = {
isa = PBXGroup;
children = (
6608A96E24E197D5006E6C68 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
6608A96124E197D5006E6C68 /* CallKitTutorial */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6608A97624E197D5006E6C68 /* Build configuration list for PBXNativeTarget "CallKitTutorial" */;
buildPhases = (
D642DC4C3C74BB17FF5A3E9F /* [CP] Check Pods Manifest.lock */,
6608A95E24E197D5006E6C68 /* Sources */,
6608A95F24E197D5006E6C68 /* Frameworks */,
6608A96024E197D5006E6C68 /* Resources */,
640A5744B5ABBA6A3EDBFDB1 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = CallKitTutorial;
productName = CallKitTutorial;
productReference = 6608A96224E197D5006E6C68 /* CallKitTutorial.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
6608A95A24E197D5006E6C68 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1160;
LastUpgradeCheck = 1160;
ORGANIZATIONNAME = BelledonneCommunications;
TargetAttributes = {
6608A96124E197D5006E6C68 = {
CreatedOnToolsVersion = 11.6;
};
};
};
buildConfigurationList = 6608A95D24E197D5006E6C68 /* Build configuration list for PBXProject "CallKitTutorial" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 6608A95924E197D5006E6C68;
productRefGroup = 6608A96324E197D5006E6C68 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
6608A96124E197D5006E6C68 /* CallKitTutorial */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
6608A96024E197D5006E6C68 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6608A97224E197D5006E6C68 /* LaunchScreen.storyboard in Resources */,
6608A96F24E197D5006E6C68 /* Preview Assets.xcassets in Resources */,
6608A96C24E197D5006E6C68 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
640A5744B5ABBA6A3EDBFDB1 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-CallKitTutorial/Pods-CallKitTutorial-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-CallKitTutorial/Pods-CallKitTutorial-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CallKitTutorial/Pods-CallKitTutorial-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
D642DC4C3C74BB17FF5A3E9F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-CallKitTutorial-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
6608A95E24E197D5006E6C68 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6608A97A24E19817006E6C68 /* CallKitTutorial.swift in Sources */,
6608A96624E197D5006E6C68 /* AppDelegate.swift in Sources */,
6608A96824E197D5006E6C68 /* SceneDelegate.swift in Sources */,
6608A96A24E197D5006E6C68 /* ContentView.swift in Sources */,
6608A97C24E1981E006E6C68 /* CallKitProviderDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
6608A97024E197D5006E6C68 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
6608A97124E197D5006E6C68 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
6608A97424E197D5006E6C68 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
6608A97524E197D5006E6C68 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
6608A97724E197D5006E6C68 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 018936DA8FE1500B9E181610 /* Pods-CallKitTutorial.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = CallKitTutorial/CallKitTutorial.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"CallKitTutorial/Preview Content\"";
DEVELOPMENT_TEAM = Z2V957B3D6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = CallKitTutorial/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.tutorials.callkit;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
6608A97824E197D5006E6C68 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C87B170DFD4D3072825B25EF /* Pods-CallKitTutorial.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = CallKitTutorial/CallKitTutorial.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"CallKitTutorial/Preview Content\"";
DEVELOPMENT_TEAM = Z2V957B3D6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = CallKitTutorial/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.tutorials.callkit;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
6608A95D24E197D5006E6C68 /* Build configuration list for PBXProject "CallKitTutorial" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6608A97424E197D5006E6C68 /* Debug */,
6608A97524E197D5006E6C68 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6608A97624E197D5006E6C68 /* Build configuration list for PBXNativeTarget "CallKitTutorial" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6608A97724E197D5006E6C68 /* Debug */,
6608A97824E197D5006E6C68 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 6608A95A24E197D5006E6C68 /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:CallKitTutorial.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,38 @@
//
// AppDelegate.swift
// CallKitTutorial
//
// Created by QuentinArguillere on 10/08/2020.
// Copyright © 2020 BelledonneCommunications. All rights reserved.
//
import UIKit
import SwiftUI
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@ObservedObject var tutorialContext = CallKitExampleContext()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}

View File

@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,99 @@
//
// ProviderDelegate.swift
// CallTutorial
//
// Created by QuentinArguillere on 05/08/2020.
// Copyright © 2020 BelledonneCommunications. All rights reserved.
//
import Foundation
import CallKit
import linphonesw
import AVFoundation
class CallKitProviderDelegate : NSObject
{
private let provider: CXProvider
let mCallController = CXCallController()
var tutorialContext : CallKitExampleContext!
var incomingCallUUID : UUID!
init(context: CallKitExampleContext)
{
tutorialContext = context
let providerConfiguration = CXProviderConfiguration(localizedName: Bundle.main.infoDictionary!["CFBundleName"] as! String)
providerConfiguration.supportsVideo = true
providerConfiguration.supportedHandleTypes = [.generic]
providerConfiguration.maximumCallsPerCallGroup = 1
providerConfiguration.maximumCallGroups = 1
provider = CXProvider(configuration: providerConfiguration)
super.init()
provider.setDelegate(self, queue: nil) // The CXProvider delegate will trigger CallKit related callbacks
}
func incomingCall()
{
incomingCallUUID = UUID()
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type:.generic, value: tutorialContext.incomingCallName)
provider.reportNewIncomingCall(with: incomingCallUUID, update: update, completion: { error in }) // Report to CallKit a call is incoming
}
func stopCall()
{
let endCallAction = CXEndCallAction(call: incomingCallUUID)
let transaction = CXTransaction(action: endCallAction)
mCallController.request(transaction, completion: { error in }) // Report to CallKit a call must end
}
}
// In this extension, we implement the action we want to be done when CallKit is notified of something.
// This can happen through the CallKit GUI in the app, or directly in the code (see, incomingCall(), stopCall() functions above)
extension CallKitProviderDelegate: CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
do {
if (tutorialContext.mCall?.state != .End && tutorialContext.mCall?.state != .Released) {
try tutorialContext.mCall?.terminate()
}
} catch { NSLog(error.localizedDescription) }
tutorialContext.isCallRunning = false
tutorialContext.isCallIncoming = false
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
do {
try tutorialContext.mCall?.accept()
tutorialContext.isCallRunning = true
} catch {
print(error)
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {}
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {}
func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {}
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {}
func providerDidReset(_ provider: CXProvider) {}
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
tutorialContext.mCore.activateAudioSession(actived: true)
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
tutorialContext.mCore.activateAudioSession(actived: false)
}
}

View File

@@ -0,0 +1,8 @@
<?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>aps-environment</key>
<string>development</string>
</dict>
</plist>

View File

@@ -0,0 +1,141 @@
//
// CallExample.swift
// CallTutorial
//
// Created by QuentinArguillere on 31/07/2020.
// Copyright © 2020 BelledonneCommunications. All rights reserved.
//
import linphonesw
import AVFoundation
class CallKitExampleContext : ObservableObject
{
var mCore: Core!
@Published var coreVersion: String = Core.getVersion
var mAccount: Account?
var mCoreDelegate : CoreDelegate!
@Published var username : String = "quentindev"
@Published var passwd : String = "dev"
@Published var domain : String = "sip.linphone.org"
@Published var loggedIn: Bool = false
@Published var transportType : String = "TLS"
@Published var callMsg : String = ""
@Published var isCallIncoming : Bool = false
@Published var isCallRunning : Bool = false
@Published var remoteAddress : String = "Nobody yet"
@Published var isSpeakerEnabled : Bool = false
@Published var isMicrophoneEnabled : Bool = false
/*------------ Callkit tutorial related variables ---------------*/
let incomingCallName = "Incoming call example"
var mCall : Call?
var mProviderDelegate : CallKitProviderDelegate!
var mCallAlreadyStopped : Bool = false;
init()
{
LoggingService.Instance.logLevel = LogLevel.Debug
let factory = Factory.Instance
// IMPORTANT : In this tutorial, we require the use of a core configuration file.
// This way, once the registration is done, and until it is cleared, it will return to the LoggedIn state on launch.
// This allows us to have a functional call when the app was closed and is started by a VOIP push notification (incoming call
// We also need to enable "Push Notitifications" and "Background Mode - Voice Over IP"
let configDir = factory.getConfigDir(context: nil)
try? mCore = factory.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil)
mProviderDelegate = CallKitProviderDelegate(context: self)
// enabling push notifications management in the core
mCore.callkitEnabled = true
mCore.pushNotificationEnabled = true
try? mCore.start()
mCoreDelegate = CoreDelegateStub( onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
self.callMsg = message
if (state == .PushIncomingReceived){
// We're being called by someone (and app is in background)
self.mCall = call
self.isCallIncoming = true
self.mProviderDelegate.incomingCall()
} else if (state == .IncomingReceived) {
// If app is in foreground, it's likely that we will receive the SIP invite before the Push notification
if (!self.isCallIncoming) {
self.mCall = call
self.isCallIncoming = true
self.mProviderDelegate.incomingCall()
}
self.remoteAddress = call.remoteAddress!.asStringUriOnly()
} else if (state == .Connected) {
self.isCallIncoming = false
self.isCallRunning = true
} else if (state == .Released || state == .End || state == .Error) {
// Call has been terminated by any side
// Report to CallKit that the call is over, if the terminate action was initiated by other end of the call
if (self.isCallRunning) {
self.mProviderDelegate.stopCall()
}
self.remoteAddress = "Nobody yet"
}
}, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString()))\n")
if (state == .Ok) {
self.loggedIn = true
// Since core has "Push Enabled", the reception and setting of the push notification token is done automatically
// It should have been set and used when we log in, you can check here or in the liblinphone logs
NSLog("Account registered Push voip token: \(account.params?.pushNotificationConfig?.voipToken)")
} else if (state == .Cleared) {
self.loggedIn = false
}
})
mCore.addDelegate(delegate: mCoreDelegate)
}
func login() {
do {
var transport : TransportType
if (transportType == "TLS") { transport = TransportType.Tls }
else if (transportType == "TCP") { transport = TransportType.Tcp }
else { transport = TransportType.Udp }
let authInfo = try Factory.Instance.createAuthInfo(username: username, userid: "", passwd: passwd, ha1: "", realm: "", domain: domain)
let accountParams = try mCore.createAccountParams()
let identity = try Factory.Instance.createAddress(addr: String("sip:" + username + "@" + domain))
try! accountParams.setIdentityaddress(newValue: identity)
let address = try Factory.Instance.createAddress(addr: String("sip:" + domain))
try address.setTransport(newValue: transport)
try accountParams.setServeraddress(newValue: address)
accountParams.registerEnabled = true
// Enable push notifications on this account
accountParams.pushNotificationAllowed = true
// We're in a sandbox application, so we must set the provider to "apns.dev" since it will be "apns" by default, which is used only for production apps
accountParams.pushNotificationConfig?.provider = "apns.dev"
mAccount = try mCore.createAccount(params: accountParams)
mCore.addAuthInfo(info: authInfo)
try mCore.addAccount(account: mAccount!)
mCore.defaultAccount = mAccount
} catch { NSLog(error.localizedDescription) }
}
func unregister()
{
if let account = mCore.defaultAccount {
let params = account.params
let clonedParams = params?.clone()
clonedParams?.registerEnabled = false
account.params = clonedParams
}
}
func delete() {
if let account = mCore.defaultAccount {
mCore.removeAccount(account: account)
mCore.clearAccounts()
mCore.clearAllAuthInfo()
}
}
}

View File

@@ -0,0 +1,116 @@
//
// ContentView.swift
// CallKit tutorial
//
// Created by QuentinArguillere on 09/09/2021.
// Copyright © 2021 BelledonneCommunications. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var tutorialContext : CallKitExampleContext
func callStateString() -> String {
if (tutorialContext.isCallRunning) {
return "Call running"
} else if (tutorialContext.isCallIncoming) {
return "Incoming call"
} else {
return "No Call"
}
}
var body: some View {
VStack {
Group {
HStack {
Text("Username:")
.font(.title)
TextField("", text : $tutorialContext.username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.disabled(tutorialContext.loggedIn)
}
HStack {
Text("Password:")
.font(.title)
TextField("", text : $tutorialContext.passwd)
.textFieldStyle(RoundedBorderTextFieldStyle())
.disabled(tutorialContext.loggedIn)
}
HStack {
Text("Domain:")
.font(.title)
TextField("", text : $tutorialContext.domain)
.textFieldStyle(RoundedBorderTextFieldStyle())
.disabled(tutorialContext.loggedIn)
}
Picker(selection: $tutorialContext.transportType, label: Text("Transport:")) {
Text("TLS").tag("TLS")
Text("TCP").tag("TCP")
Text("UDP").tag("UDP")
}.pickerStyle(SegmentedPickerStyle()).padding()
VStack {
HStack {
Button(action: {
if (self.tutorialContext.loggedIn)
{
self.tutorialContext.unregister()
self.tutorialContext.delete()
} else {
self.tutorialContext.login()
}
})
{
Text(tutorialContext.loggedIn ? "Log out & \ndelete account" : "Create & \nlog in account")
.font(.largeTitle)
.foregroundColor(Color.white)
.frame(width: 220.0, height: 90)
.background(Color.gray)
}
}
HStack {
Text("Login State : ")
.font(.footnote)
Text(tutorialContext.loggedIn ? "Looged in" : "Unregistered")
.font(.footnote)
.foregroundColor(tutorialContext.loggedIn ? Color.green : Color.black)
}.padding(.top, 10.0)
}
VStack {
HStack {
Text("Caller:").font(.title).underline()
Text(tutorialContext.remoteAddress)
Spacer()
}.padding(.top, 5)
HStack {
Text("Call msg:").font(.title3).underline()
Text(tutorialContext.callMsg)
Spacer()
}.padding(.top, 5)
}.padding(.top, 30)
Button(action: tutorialContext.mProviderDelegate.stopCall)
{
Text("End call").font(.largeTitle)
.foregroundColor(Color.white)
.frame(width: 120.0, height: 42.0)
.background(Color.gray)
}.disabled(!tutorialContext.isCallRunning)
.padding(.top, 10)
}
Group {
Spacer()
Text("Core Version is \(tutorialContext.coreVersion)")
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(tutorialContext: CallKitExampleContext())
}
}

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Camera access</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,66 @@
//
// SceneDelegate.swift
// CallKitTutorial
//
// Created by QuentinArguillere on 10/08/2020.
// Copyright © 2020 BelledonneCommunications. All rights reserved.
//
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let delegate = UIApplication.shared.delegate as! AppDelegate
let contentView = ContentView(tutorialContext: delegate.tutorialContext)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}

View File

@@ -0,0 +1,24 @@
# Uncomment the next line to define a global platform for your project
platform :ios, '11.0'
source "https://gitlab.linphone.org/BC/public/podspec.git"
source "https://github.com/CocoaPods/Specs.git"
def basic_pods
if ENV['PODFILE_PATH'].nil?
pod 'linphone-sdk', '~> 5.0.0'
else
pod 'linphone-sdk', :path => ENV['PODFILE_PATH'] # local sdk
end
end
target 'CallKitTutorial' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for CallKitTutorial
basic_pods
end

View File

@@ -0,0 +1,10 @@
Push notifications tutorial
====================
On mobile devices (Android & iOS), you probably want your app to be reachable even if it's not in the foreground.
To do that you need it to be able to receive push notifications from your SIP proxy, and in this tutorial, using [Apple Push Notification Service](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html), you'll learn how to simply send the device push information to your server.
Apple will also require you to use their CallKit API when you receive a push notification, you must always notify CallKit when you receive a VOIP Push or your app will be terminated. If you use the "Core.pushEnabled=true" settings, as is done in this app, most of this work is done in the sdk and you only require to notify an incoming call when your Core Delegate notifies you of a new call.
Compared to the previous tutorials, some changes have been required in `CallKitTutorial.xcodeproj` in order to enable `Push Notifications` and `BackGround Modes (Voice Over IP)` in the capabilities of your project.