diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 19124c991..a585e72a0 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -55,7 +55,7 @@ jobs:
exit $INTEGRATION_TEST_EXIT_CODE
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: result.mkv
path: commet/video.mkv
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 49b8f30e0..c3c7766bd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -162,4 +162,160 @@ jobs:
- name: Build Web
run: |
cd $PROJECT_PATH
- flutter build web --release --dart-define PLATFORM=web
\ No newline at end of file
+ flutter build web --release --dart-define PLATFORM=web
+
+ build-mac:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: 'true'
+
+ - name: Setup Flutter
+ uses: subosito/flutter-action@v2.8.0
+ with:
+ flutter-version: '3.24.4'
+ channel: 'stable'
+
+ - name: Setup Provisioning Profile
+ env:
+ BUILD_CERTIFICATE_BASE64: ${{ secrets.MACOS_SIGNING_P12 }}
+ P12_PASSWORD: ${{ secrets.MACOS_SIGNING_P12_PASSWORD }}
+ BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.COMMET_MACOS_PROVISIONPROFILE }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+ run: |
+ # create variables
+ CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
+ PP_PATH=$RUNNER_TEMP/build_pp.provisionprofile
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+
+ # import certificate and provisioning profile from secrets
+ echo "Making Build Certificate"
+ echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
+ echo "Making Provisioning Profile"
+ echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
+
+ # create temporary keychain
+ security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+
+ # import certificate to keychain
+ security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+ security list-keychain -d user -s $KEYCHAIN_PATH
+
+ # apply provisioning profile
+ mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
+ cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/
+
+ - name: Create Configuration
+ run: |
+ cd $PROJECT_PATH/macos/Runner/Configs
+ touch AppInfo.xcconfig
+ echo PRODUCT_NAME=commet >> AppInfo.xcconfig
+ echo PRODUCT_BUNDLE_IDENTIFIER=${{ vars.MACOS_BUNDLE_ID }} >> AppInfo.xcconfig
+ echo PRODUCT_COPYRIGHT="Copyright © 2023 commet.chat. All rights reserved." >> AppInfo.xcconfig
+ echo PRODUCT_TEAM=${{ secrets.DEV_TEAM_ID }} >> AppInfo.xcconfig
+ echo PRODUCT_PROFILE=${{ secrets.MACOS_PROVISIONING_PROFILE_NAME }} >> AppInfo.xcconfig
+
+ - name: Code Generation
+ run: |
+ cd $PROJECT_PATH
+ dart run scripts/codegen.dart
+
+ - name: Build Mac
+ run: |
+ cd $PROJECT_PATH
+ flutter build macos --dart-define BUILD_MODE=release --dart-define PLATFORM=macos
+
+ - name: Clean up keychain and provisioning profile
+ if: ${{ always() }}
+ run: |
+ security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
+ rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.provisionprofile
+
+ build-ios:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: 'true'
+
+ - name: Setup Flutter
+ uses: subosito/flutter-action@v2.8.0
+ with:
+ flutter-version: '3.24.4'
+ channel: 'stable'
+
+ - name: Setup Provisioning Profile
+ env:
+ BUILD_CERTIFICATE_BASE64: ${{ secrets.IOS_SIGNING_P12 }}
+ P12_PASSWORD: ${{ secrets.IOS_SIGNING_P12_PASSWORD }}
+ BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.COMMET_IOS_MOBILEPROVISION }}
+ BUILD_EXTENSION_PROVISION_PROFILE_BASE64: ${{ secrets.COMMET_IOS_EXTENSION_MOBILEPROVISION }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+ run: |
+ # create variables
+ CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
+ PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
+ PP_EXT_PATH=$RUNNER_TEMP/build_ext_pp.mobileprovision
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+
+ # import certificate and provisioning profile from secrets
+ echo "Making Build Certificate"
+ echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
+ echo "Making Provisioning Profile"
+ echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
+ echo "Making Extension Provisioning Profile"
+ echo -n "$BUILD_EXTENSION_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_EXT_PATH
+
+ # create temporary keychain
+ security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+
+ # import certificate to keychain
+ security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+ security list-keychain -d user -s $KEYCHAIN_PATH
+
+ # apply provisioning profile
+ mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
+ cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/
+ cp $PP_EXT_PATH ~/Library/MobileDevice/Provisioning\ Profiles/
+
+ - name: Create Configuration
+ run: |
+ cd $PROJECT_PATH/ios
+ touch AppInfo.xcconfig
+ echo PRODUCT_NAME=commet >> AppInfo.xcconfig
+ echo PRODUCT_BUNDLE_IDENTIFIER=${{ vars.IOS_BUNDLE_ID }} >> AppInfo.xcconfig
+ echo PRODUCT_SERVICE_BUNDLE_IDENTIFIER=${{ vars.IOS_BUNDLE_SERVICER_ID }} >> AppInfo.xcconfig
+ echo PRODUCT_COPYRIGHT="Copyright © 2023 commet.chat. All rights reserved." >> AppInfo.xcconfig
+ echo PRODUCT_TEAM=${{ secrets.DEV_TEAM_ID }} >> AppInfo.xcconfig
+ echo PRODUCT_PROFILE=${{ secrets.IOS_PROVISIONING_PROFILE_NAME }} >> AppInfo.xcconfig
+ echo PRODUCT_SERVICE_PROFILE=${{ secrets.IOS_EXTENSION_PROVISIONING_PROFILE_NAME }} >> AppInfo.xcconfig
+
+ - name: Code Generation
+ run: |
+ cd $PROJECT_PATH
+ gem install plist_lite
+ dart run scripts/codegen.dart
+ cd ios
+ pod install
+
+ - name: Build iOS
+ env:
+ GATEWAY: ${{ vars.IOS_PUSH_GATEWAY }}
+ run: |
+ cd $PROJECT_PATH
+ flutter build ipa --export-options-plist=ios/export.plist --dart-define BUILD_MODE=release --dart-define PLATFORM=ios --dart-define PUSH_GATEWAY=$GATEWAY
+
+ - name: Clean up keychain and provisioning profile
+ if: ${{ always() }}
+ run: |
+ security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
+ rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml
index ee7151acb..c63b4677f 100644
--- a/.github/workflows/integration-test.yml
+++ b/.github/workflows/integration-test.yml
@@ -67,7 +67,7 @@ jobs:
- name: Upload Artifact
if: failure()
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: result.mkv
path: commet/video.mkv
diff --git a/README.md b/README.md
index 6b5aa1047..cfdf43dfe 100644
--- a/README.md
+++ b/README.md
@@ -74,15 +74,15 @@ When building Commet, there are some additional command line arguments that must
**Required**
| **Argument** | **Valid Values** | **Description** |
|--------------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
-| PLATFORM | 'desktop', 'mobile', 'linux', 'windows', 'macos', 'android', 'ios', 'web' | Defines which platform to build for |
+| PLATFORM | 'desktop', 'mobile', 'linux', 'windows', 'macos', 'android', 'ios', 'web' | Defines which platform to build for |
| BUILD_MODE | 'release', 'debug' | When building with 'debug' flag, additional debug information will be shown |
**Optional**
-| **Argument** | **Valid Values** | **Description** |
-|--------------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
-| GIT_HASH | * | Supply the current git hash when building to show in info screen |
-| VERSION_TAG | * | Supply the current build version, to display app version |
-| BUILD_DETAIL | * | Can provide additional detail about the current build, for example if it was being built for Flatpak or Snap |
+| **Argument** | **Valid Values** | **Description** |
+|--------------|------------------|--------------------------------------------------------------------------------------------------------------|
+| GIT_HASH | * | Supply the current git hash when building to show in info screen |
+| VERSION_TAG | * | Supply the current build version, to display app version |
+| BUILD_DETAIL | * | Can provide additional detail about the current build, for example if it was being built for Flatpak or Snap |
**Example:**
@@ -90,3 +90,37 @@ When building Commet, there are some additional command line arguments that must
cd commet
flutter run --dart-define BUILD_MODE=debug --dart-define PLATFORM=linux
```
+
+## Building on macOS
+
+These are rough notes, based on the experience of getting Commet compiled and running for
+macOS and iOS from a mac.
+
+- Install [Homebrew](https://brew.sh)
+- Install ninja with `brew install ninja`
+ - Repeat for "gtk", "mpv", "ffmpeg", "libmpv", "mimalloc"
+- If you want to run locally only (on a mac), you can install OLM with
+ `brew install libolm`. If you want to generate a universal binary, then the Commet
+ Xcode project for macOS includes a Cocoapods installation of "OLMKit" along with a shell
+ script to create an alias to the compiled library named "libolm.3.dylib", so that the
+ application can find it.
+- For both macOS and iOS, open the Xcode projects by opening the ".xcworkspace" file
+ instead of the ".xcodeproj" file.
+ - In these files, set up code signing appropriately. You will need:
+ - An apple code signing certificate for iOS (and the same for macOS if you want to be
+ able to run the app non-locally)
+ - An Apple Push Services certificate for push notification support
+ - An Apple Identifier for your app bundle name (e.g. "chat.commet.app.WHATEVER")
+ - An Apple device profile for each device (mac or phone) you want to test on
+ - An Apple services key for push services (and your own Firebase set-up to go with it)
+ if you want to use push notifications outside of the main commet set-up
+
+The current set-up specifies the Podfile for both macOS and iOS (rather than having
+Flutter generate it) because the generated Podfile both sets the wrong target OS versions
+and includes a test target which is not actually present in the code. In addition, on
+macOS, the pod install of 'OLMKit' *must* be done manually in the pod file because the
+Flutter pod definition of OLMKit will only install it on iOS, and Homebrew will only
+install the version of libolm that matches the system architecture on which it's running.
+In addition, the Homebrew libolm is linked with the rest of the homebrew installation, and
+thus the library may fail to work, even embedded in the app, if installed on a different
+system.
diff --git a/commet/ios/Flutter/AppFrameworkInfo.plist b/commet/ios/Flutter/AppFrameworkInfo.plist
index 9625e105d..7c5696400 100644
--- a/commet/ios/Flutter/AppFrameworkInfo.plist
+++ b/commet/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 11.0
+ 12.0
diff --git a/commet/ios/Flutter/Debug.xcconfig b/commet/ios/Flutter/Debug.xcconfig
index 592ceee85..ec97fc6f3 100644
--- a/commet/ios/Flutter/Debug.xcconfig
+++ b/commet/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/commet/ios/Flutter/Release.xcconfig b/commet/ios/Flutter/Release.xcconfig
index 592ceee85..c4855bfe2 100644
--- a/commet/ios/Flutter/Release.xcconfig
+++ b/commet/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/commet/ios/Podfile b/commet/ios/Podfile
new file mode 100644
index 000000000..7e6138aa8
--- /dev/null
+++ b/commet/ios/Podfile
@@ -0,0 +1,107 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '13.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+require 'plist_lite'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+
+ target.build_configurations.each do |config|
+ # You can remove unused permissions here
+ # for more information: https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
+ # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
+ '$(inherited)',
+
+ ## dart: PermissionGroup.notification
+ 'PERMISSION_NOTIFICATIONS=1',
+ ]
+
+ end
+ end
+
+ work_dir = Dir.pwd
+ app_id = ""
+ app_profile = ""
+ service_id = ""
+ service_profile = ""
+ team_id = ""
+ env_path = "#{work_dir}/Appinfo.xcconfig"
+ File.foreach( env_path ) do |line|
+ items = line.split("=")
+ if ("#{items[0]}" == "PRODUCT_SERVICE_BUNDLE_IDENTIFIER") then
+ service_id = items[1].strip!
+ elsif ("#{items[0]}" == "PRODUCT_BUNDLE_IDENTIFIER") then
+ app_id = items[1].strip!
+ elsif ("#{items[0]}" == "PRODUCT_TEAM") then
+ team_id = items[1].strip!
+ elsif ("#{items[0]}" == "PRODUCT_PROFILE") then
+ app_profile = items[1].strip!
+ elsif ("#{items[0]}" == "PRODUCT_SERVICE_PROFILE") then
+ service_profile = items[1].strip!
+ end
+ end
+ Dir.glob("Pods/Target Support Files/Pods-servicer/*.xcconfig") do |xc_config_filename|
+ full_path_name = "#{work_dir}/#{xc_config_filename}"
+ if (File.exist?(full_path_name))
+ new_text = "PRODUCT_BUNDLE_IDENTIFIER = #{service_id}\n"
+ end
+ File.write(full_path_name, new_text, File.size(full_path_name), mode: 'a')
+ end
+ export_path = File.expand_path(File.join('..', "export.plist"), __FILE__)
+ puts "Export file path is #{export_path}"
+ provisioning_profiles={app_id => app_profile, service_id => service_profile}
+ plist = {
+ "destination" => "export",
+ "manageAppVersionAndBuildNumber" => true,
+ "method" => "app-store-connect",
+ "provisioningProfiles" => provisioning_profiles,
+ "signingCertificate" => "Apple Distribution",
+ "signingStyle" => "manual",
+ "stripSwiftSymbols" => true,
+ "teamID" => team_id,
+ "uploadSymbols" => true
+ }
+ puts plist
+ plist_text = PlistLite.dump(plist)
+ puts plist_text
+ File.open(export_path, "w") {|file| file.puts PlistLite.dump(plist) }
+end
+
+target 'servicer' do
+ use_frameworks!
+end
diff --git a/commet/ios/Runner.xcodeproj/project.pbxproj b/commet/ios/Runner.xcodeproj/project.pbxproj
index c6503b75e..5cafe174d 100644
--- a/commet/ios/Runner.xcodeproj/project.pbxproj
+++ b/commet/ios/Runner.xcodeproj/project.pbxproj
@@ -3,19 +3,45 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 54;
+ objectVersion = 63;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 33094CB8717F20131D8A6C51 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF23A21167A1629A46938202 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 600CAF462D8B2821002E12F6 /* AppInfo.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */; };
+ 600CB14A2D8F2B0A002E12F6 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 600CB1432D8F2B0A002E12F6 /* NotificationService.swift */; };
+ 6021A3252D828F45001F0660 /* servicer.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 6021A31E2D828F45001F0660 /* servicer.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ F0DC56CC087774C439052C75 /* Pods_servicer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 182DFD5CBE07ACC7F7E761BC /* Pods_servicer.framework */; };
/* End PBXBuildFile section */
+/* Begin PBXContainerItemProxy section */
+ 6021A3232D828F45001F0660 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6021A31D2D828F45001F0660;
+ remoteInfo = servicer;
+ };
+/* End PBXContainerItemProxy section */
+
/* Begin PBXCopyFilesBuildPhase section */
+ 6021A3262D828F45001F0660 /* Embed Foundation Extensions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 13;
+ files = (
+ 6021A3252D828F45001F0660 /* servicer.appex in Embed Foundation Extensions */,
+ );
+ name = "Embed Foundation Extensions";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -29,9 +55,20 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 0D317BE01B771C2F83770B29 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 182DFD5CBE07ACC7F7E761BC /* Pods_servicer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_servicer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 57C41A2591C5EDD8E3475A60 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
+ 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; };
+ 600CB1422D8F2B0A002E12F6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 600CB1432D8F2B0A002E12F6 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; };
+ 600CB1442D8F2B0A002E12F6 /* servicer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = servicer.entitlements; sourceTree = ""; };
+ 600D31202D83386000F738D9 /* Flutter.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:S8QB4VV633:FLUTTER.IO LLC"; lastKnownFileType = wrapper.xcframework; name = Flutter.xcframework; path = "../../../flutter-sdk/bin/cache/artifacts/engine/ios/extension_safe/Flutter.xcframework"; sourceTree = ""; };
+ 6021A31E2D828F45001F0660 /* servicer.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = servicer.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ 603701A52D728005004FE230 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
+ 6F71ADEFB749D97791F21965 /* Pods-servicer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-servicer.debug.xcconfig"; path = "Target Support Files/Pods-servicer/Pods-servicer.debug.xcconfig"; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -42,19 +79,52 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ ABF91C8D62261D1B58A78884 /* Pods-servicer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-servicer.release.xcconfig"; path = "Target Support Files/Pods-servicer/Pods-servicer.release.xcconfig"; sourceTree = ""; };
+ D0E55B5F3A40F501ACD4023C /* Pods-servicer.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-servicer.profile.xcconfig"; path = "Target Support Files/Pods-servicer/Pods-servicer.profile.xcconfig"; sourceTree = ""; };
+ DD5B2EEE2F68770E413E08AF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ DF23A21167A1629A46938202 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 6021A31B2D828F45001F0660 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F0DC56CC087774C439052C75 /* Pods_servicer.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 33094CB8717F20131D8A6C51 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 5F731FA9B1EF6A5DF5DC817A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 600D31202D83386000F738D9 /* Flutter.xcframework */,
+ DF23A21167A1629A46938202 /* Pods_Runner.framework */,
+ 182DFD5CBE07ACC7F7E761BC /* Pods_servicer.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 600CB1452D8F2B0A002E12F6 /* servicer */ = {
+ isa = PBXGroup;
+ children = (
+ 600CB1422D8F2B0A002E12F6 /* Info.plist */,
+ 600CB1432D8F2B0A002E12F6 /* NotificationService.swift */,
+ 600CB1442D8F2B0A002E12F6 /* servicer.entitlements */,
+ );
+ path = servicer;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -71,7 +141,11 @@
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
+ 600CB1452D8F2B0A002E12F6 /* servicer */,
97C146EF1CF9000F007C117D /* Products */,
+ AAF1D69EC431FC127C369128 /* Pods */,
+ 5F731FA9B1EF6A5DF5DC817A /* Frameworks */,
+ 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */,
);
sourceTree = "";
};
@@ -79,6 +153,7 @@
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
+ 6021A31E2D828F45001F0660 /* servicer.appex */,
);
name = Products;
sourceTree = "";
@@ -86,6 +161,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ 603701A52D728005004FE230 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -98,23 +174,59 @@
path = Runner;
sourceTree = "";
};
+ AAF1D69EC431FC127C369128 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 0D317BE01B771C2F83770B29 /* Pods-Runner.debug.xcconfig */,
+ DD5B2EEE2F68770E413E08AF /* Pods-Runner.release.xcconfig */,
+ 57C41A2591C5EDD8E3475A60 /* Pods-Runner.profile.xcconfig */,
+ 6F71ADEFB749D97791F21965 /* Pods-servicer.debug.xcconfig */,
+ ABF91C8D62261D1B58A78884 /* Pods-servicer.release.xcconfig */,
+ D0E55B5F3A40F501ACD4023C /* Pods-servicer.profile.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
+ 6021A31D2D828F45001F0660 /* servicer */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 6021A32B2D828F45001F0660 /* Build configuration list for PBXNativeTarget "servicer" */;
+ buildPhases = (
+ 0B5A74AC87AAFB82FC770C06 /* [CP] Check Pods Manifest.lock */,
+ 6021A31A2D828F45001F0660 /* Sources */,
+ 6021A31B2D828F45001F0660 /* Frameworks */,
+ 6021A31C2D828F45001F0660 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = servicer;
+ productName = servicer;
+ productReference = 6021A31E2D828F45001F0660 /* servicer.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ A06759ECA63285C3A4F0528E /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 6021A3262D828F45001F0660 /* Embed Foundation Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ B7544AEBA57AB2081ADCD564 /* [CP] Embed Pods Frameworks */,
+ 006FB0C14E09DB927049DA3C /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
+ 6021A3242D828F45001F0660 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
@@ -127,9 +239,13 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1300;
+ LastSwiftUpdateCheck = 1620;
+ LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
+ 6021A31D2D828F45001F0660 = {
+ CreatedOnToolsVersion = 16.2;
+ };
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
@@ -137,7 +253,7 @@
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
- compatibilityVersion = "Xcode 9.3";
+ compatibilityVersion = "Xcode 15.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -150,11 +266,20 @@
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
+ 6021A31D2D828F45001F0660 /* servicer */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 6021A31C2D828F45001F0660 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 600CAF462D8B2821002E12F6 /* AppInfo.xcconfig in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -169,6 +294,45 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
+ 006FB0C14E09DB927049DA3C /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 0B5A74AC87AAFB82FC770C06 /* [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-servicer-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;
+ };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -176,6 +340,7 @@
files = (
);
inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@@ -199,9 +364,56 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ A06759ECA63285C3A4F0528E /* [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-Runner-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;
+ };
+ B7544AEBA57AB2081ADCD564 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 6021A31A2D828F45001F0660 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 600CB14A2D8F2B0A002E12F6 /* NotificationService.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -213,6 +425,14 @@
};
/* End PBXSourcesBuildPhase section */
+/* Begin PBXTargetDependency section */
+ 6021A3242D828F45001F0660 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6021A31D2D828F45001F0660 /* servicer */;
+ targetProxy = 6021A3232D828F45001F0660 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
@@ -235,6 +455,7 @@
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -274,7 +495,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -288,24 +509,167 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = chat.commet.commetapp;
+ PRODUCT_BUNDLE_IDENTIFIER = chat.commet.commetapp.quirt;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_distribution;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
+ 6021A3272D828F45001F0660 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 6F71ADEFB749D97791F21965 /* Pods-servicer.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = "$(inherited)";
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = servicer/servicer.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = servicer/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = servicer;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_extension_distribution;
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 6021A3282D828F45001F0660 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = ABF91C8D62261D1B58A78884 /* Pods-servicer.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = "$(inherited)";
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = servicer/servicer.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = servicer/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = servicer;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_extension_distribution;
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 6021A3292D828F45001F0660 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D0E55B5F3A40F501ACD4023C /* Pods-servicer.profile.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = "$(inherited)";
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = servicer/servicer.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = servicer/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = servicer;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_extension_distribution;
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -351,7 +715,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -361,6 +725,7 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 600CAF452D8B2821002E12F6 /* AppInfo.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -400,7 +765,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -416,16 +781,26 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = chat.commet.commetapp;
+ PRODUCT_BUNDLE_IDENTIFIER = "--PRODUCT-BUNDLE-IDENTIFIER-";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_distribution;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -438,16 +813,26 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
+ CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = J6B4LYQ6NB;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = chat.commet.commetapp;
+ PRODUCT_BUNDLE_IDENTIFIER = chat.commet.commetapp.quirt;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = commet_ios_distribution;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -457,6 +842,16 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 6021A32B2D828F45001F0660 /* Build configuration list for PBXNativeTarget "servicer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6021A3272D828F45001F0660 /* Debug */,
+ 6021A3282D828F45001F0660 /* Release */,
+ 6021A3292D828F45001F0660 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/commet/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/commet/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index c87d15a33..5e31d3d34 100644
--- a/commet/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/commet/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
+
+
diff --git a/commet/ios/Runner/AppDelegate.swift b/commet/ios/Runner/AppDelegate.swift
index 70693e4a8..f0e7131ee 100644
--- a/commet/ios/Runner/AppDelegate.swift
+++ b/commet/ios/Runner/AppDelegate.swift
@@ -1,13 +1,105 @@
import UIKit
import Flutter
+import UserNotifications
-@UIApplicationMain
+@main
@objc class AppDelegate: FlutterAppDelegate {
+
+ let channelName : String = "PushNotificationChannel"
+ var deviceToken : String = ""
+
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
+ let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
+ let pushNotificationChannel = FlutterMethodChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
+ if #available(iOS 10.0, *) {
+ UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
+ }
+
+ pushNotificationChannel.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in
+ switch call.method {
+ case "requestNotificationPermissions":
+ self?.requestNotificationPermissions(result: result)
+ case "registerForPushNotifications":
+ self?.registerForPushNotifications(application: application, result: result)
+ case "retrieveDeviceToken":
+ self?.getDeviceToken(result: result)
+ default:
+ result(FlutterMethodNotImplemented)
+ }
+ }
+
GeneratedPluginRegistrant.register(with: self)
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+
+ override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+ let deviceTokenString = deviceToken.reduce("", { $0 + String(format: "%02X", $1) })
+ let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
+ let pushNotificationChannel = FlutterMethodChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
+ self.deviceToken = deviceTokenString
+ pushNotificationChannel.invokeMethod("didRegister", arguments: deviceTokenString)
+ }
+
+ override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
+ }
+
+
+
+ private func requestNotificationPermissions(result: @escaping FlutterResult) {
+ UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
+ if let error = error {
+ result(FlutterError(code: "PERMISSION_ERROR", message: "Failed to request permissions", details: error.localizedDescription))
+ return
+ }
+ result(granted)
+ }
+ }
+
+ private func registerForPushNotifications(application: UIApplication, result: @escaping FlutterResult) {
+ application.registerForRemoteNotifications()
+ result("Device Token registration initiated")
+ }
+
+ private func getDeviceToken(result: @escaping FlutterResult) {
+ if(deviceToken.isEmpty) {
+ result(FlutterError(code: "UNAVAILABLE", message: "Device token not available", details: nil))
+ } else {
+ result(deviceToken)
+ }
+ }
+
+ override func application(_ application: UIApplication,
+ didReceiveRemoteNotification userInfo: [AnyHashable: Any],
+ fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
+ handleNotification(methodName: "onBackgroundNotification", userInfo: userInfo)
+ completionHandler(UIBackgroundFetchResult.noData)
+ }
+
+ override func userNotificationCenter(_ center: UNUserNotificationCenter,
+ willPresent notification: UNNotification,
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+ if #available(iOS 14.0, *) {
+ completionHandler([.banner, .list, .sound, .badge])
+ } else {
+ completionHandler([.alert, .sound, .badge])
+ }
+ }
+
+ override func userNotificationCenter(_ center: UNUserNotificationCenter,
+ didReceive response: UNNotificationResponse,
+ withCompletionHandler completionHandler: @escaping () -> Void) {
+ let userInfo = response.notification.request.content.userInfo
+ handleNotification(methodName: "onPushNotification", userInfo: userInfo)
+ completionHandler()
+ }
+
+ private func handleNotification(methodName: String, userInfo: [AnyHashable: Any]) {
+ let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
+ let pushNotificationChannel = FlutterMethodChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
+ pushNotificationChannel.invokeMethod(methodName, arguments: userInfo)
}
}
diff --git a/commet/ios/Runner/Info.plist b/commet/ios/Runner/Info.plist
index 0fb038ed1..e701f920a 100644
--- a/commet/ios/Runner/Info.plist
+++ b/commet/ios/Runner/Info.plist
@@ -2,6 +2,16 @@
+ BGTaskScheduler
+
+ dev.flutter.background.refresh
+
+ BGTaskSchedulerPermittedIdentifiers
+
+ dev.flutter.background.refresh
+
+ CADisableMinimumFrameDurationOnPhone
+
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
@@ -22,8 +32,22 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ FirebaseAppDelegateProxyEnabled
+
+ ITSAppUsesNonExemptEncryption
+
LSRequiresIPhoneOS
+ NSPhotoLibraryUsageDescription
+ Commet requests access to your photo library in order to allow you to share photos in your Matrix servers and rooms.
+ UIApplicationSupportsIndirectInputEvents
+
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+ processing
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
@@ -43,9 +67,5 @@
UIViewControllerBasedStatusBarAppearance
- CADisableMinimumFrameDurationOnPhone
-
- UIApplicationSupportsIndirectInputEvents
-
diff --git a/commet/ios/Runner/Runner.entitlements b/commet/ios/Runner/Runner.entitlements
new file mode 100644
index 000000000..fb5eb5be7
--- /dev/null
+++ b/commet/ios/Runner/Runner.entitlements
@@ -0,0 +1,12 @@
+
+
+
+
+ aps-environment
+ development
+ com.apple.security.application-groups
+
+ group.commet.ios
+
+
+
diff --git a/commet/ios/servicer/Info.plist b/commet/ios/servicer/Info.plist
new file mode 100644
index 000000000..57421ebf9
--- /dev/null
+++ b/commet/ios/servicer/Info.plist
@@ -0,0 +1,13 @@
+
+
+
+
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.service
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).NotificationService
+
+
+
diff --git a/commet/ios/servicer/NotificationService.swift b/commet/ios/servicer/NotificationService.swift
new file mode 100644
index 000000000..f1ed58445
--- /dev/null
+++ b/commet/ios/servicer/NotificationService.swift
@@ -0,0 +1,48 @@
+//
+// NotificationService.swift
+// servicer
+//
+// Created by Brian Quirt on 3/12/25.
+//
+
+import UserNotifications
+
+class NotificationService: UNNotificationServiceExtension {
+
+ var contentHandler: ((UNNotificationContent) -> Void)?
+ var bestAttemptContent: UNMutableNotificationContent?
+
+ override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
+ self.contentHandler = contentHandler
+ bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
+
+ if let bestAttemptContent = bestAttemptContent {
+ var displayRoom : String = ""
+ let roomId = bestAttemptContent.userInfo["room_id"] as! String
+ if roomId.contains(":") {
+ let roomCode = roomId.lastIndex(of:":")!
+ displayRoom = String(roomId[roomCode...])
+ } else {
+ displayRoom = roomId
+ }
+ let unreadCount = bestAttemptContent.userInfo["unread_count"] as! Int
+
+ bestAttemptContent.title = "\(displayRoom)"
+ bestAttemptContent.subtitle = "\(unreadCount) new message(s)"
+ bestAttemptContent.body = "Tap on this message to be taken to the room where it happened™️"
+
+ contentHandler(bestAttemptContent)
+ }
+ }
+
+ override func serviceExtensionTimeWillExpire() {
+ // Called just before the extension will be terminated by the system.
+ // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
+ if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
+ bestAttemptContent.title = "New Matrix Message"
+ bestAttemptContent.body = "Tap on this message to be taken to the room where it happened™️"
+ contentHandler(bestAttemptContent)
+ }
+ }
+
+}
diff --git a/commet/ios/servicer/servicer.entitlements b/commet/ios/servicer/servicer.entitlements
new file mode 100644
index 000000000..476981528
--- /dev/null
+++ b/commet/ios/servicer/servicer.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.commet.ios
+
+
+
diff --git a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart b/commet/lib/client/components/push_notification/firebase_push_notifier.dart
similarity index 99%
rename from commet/lib/client/components/push_notification/android/firebase_push_notifier.dart
rename to commet/lib/client/components/push_notification/firebase_push_notifier.dart
index 75e6f5bf9..3fb07f929 100644
--- a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart
+++ b/commet/lib/client/components/push_notification/firebase_push_notifier.dart
@@ -65,7 +65,7 @@ Future _firebaseMessagingBackgroundHandler(dynamic message) async {
}
class FirebasePushNotifier implements Notifier {
- late AndroidNotifier notifier;
+ late Notifier notifier;
@override
bool get hasPermission => notifier.hasPermission;
diff --git a/commet/lib/client/components/push_notification/ios/ios_mutable_notifier.dart b/commet/lib/client/components/push_notification/ios/ios_mutable_notifier.dart
new file mode 100644
index 000000000..e40b6503f
--- /dev/null
+++ b/commet/lib/client/components/push_notification/ios/ios_mutable_notifier.dart
@@ -0,0 +1,75 @@
+import 'dart:async';
+
+import 'package:commet/cache/file_cache.dart';
+import 'package:commet/client/client_manager.dart';
+import 'package:commet/client/member.dart';
+import 'package:commet/client/timeline_events/timeline_event_encrypted.dart';
+import 'package:commet/debug/log.dart';
+import 'package:commet/main.dart';
+
+class IOSNotificationMutator {
+ Completer completer;
+
+ IOSNotificationMutator(this.completer);
+
+ Future init() async {
+ isHeadless = true;
+
+ if (fileCache == null) {
+ fileCache = FileCache.getFileCacheInstance();
+
+ if (fileCache != null) {
+ await fileCache?.init();
+ }
+ }
+
+ shortcutsManager.init();
+
+ clientManager = await ClientManager.init(isBackgroundService: true);
+ }
+
+ Future