aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2022-02-12 01:20:35 -0600
committerIván Ávalos <avalos@disroot.org>2022-02-12 01:20:35 -0600
commit8098ae108e59d3170f88379d8aa51363036ea5eb (patch)
tree820c176c6bcd7dbe92e658b735cb2bf98317a13a
parentaa8dd06acac37244420d5dcb6b83c74153563ae5 (diff)
downloadetbsa-trackermap-mobile-8098ae108e59d3170f88379d8aa51363036ea5eb.tar.gz
etbsa-trackermap-mobile-8098ae108e59d3170f88379d8aa51363036ea5eb.tar.bz2
etbsa-trackermap-mobile-8098ae108e59d3170f88379d8aa51363036ea5eb.zip
WIP: FCM notifications (not working)
-rw-r--r--iosApp/.gitignore6
-rw-r--r--iosApp/iosApp.xcodeproj/project.pbxproj37
-rw-r--r--iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved108
-rw-r--r--iosApp/iosApp/AppDelegate.swift59
-rw-r--r--iosApp/iosApp/Info.plist4
-rw-r--r--iosApp/iosApp/Session/RootView.swift10
-rw-r--r--iosApp/iosApp/iOSApp.swift1
-rw-r--r--iosApp/iosApp/iosApp.entitlements8
8 files changed, 229 insertions, 4 deletions
diff --git a/iosApp/.gitignore b/iosApp/.gitignore
index 1342544..cfbc7b3 100644
--- a/iosApp/.gitignore
+++ b/iosApp/.gitignore
@@ -88,4 +88,8 @@ fastlane/test_output
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
-iOSInjectionProject/ \ No newline at end of file
+iOSInjectionProject/
+
+# Firebase
+
+GoogleService-Info.plist
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index 2be5d57..b3e7b29 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -21,6 +21,7 @@
E33A237327A7581A00DD647F /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A237227A7581A00DD647F /* Utils.swift */; };
E34A2F4827A7878200AD8AEB /* HyperlinkText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34A2F4727A7878200AD8AEB /* HyperlinkText.swift */; };
E34A2F4D27A7DB2200AD8AEB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E34A2F4C27A7DB2200AD8AEB /* Localizable.strings */; };
+ E36A5A8627B4BFC40070DED5 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */; };
E36DF77B27AB740C003C561C /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36DF77927AB740C003C561C /* MapViewController.swift */; };
E36DF77C27AB740C003C561C /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E36DF77A27AB740C003C561C /* MapViewController.xib */; };
E38F241527A242870069FC45 /* Inject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241427A242870069FC45 /* Inject.swift */; };
@@ -28,6 +29,8 @@
E38F241C27A26DD70069FC45 /* RootViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241B27A26DD70069FC45 /* RootViewModel.swift */; };
E38F241E27A270D50069FC45 /* UnitsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241D27A270D50069FC45 /* UnitsView.swift */; };
E38F242027A27B550069FC45 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241F27A27B550069FC45 /* LoadingView.swift */; };
+ E392BE1727B77B7E002698F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E392BE1627B77B7E002698F3 /* AppDelegate.swift */; };
+ E392BE1927B791F0002698F3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E392BE1827B791F0002698F3 /* GoogleService-Info.plist */; };
E396281D27AF5723005D070E /* WhirlyGlobe.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */; };
E396281E27AF5723005D070E /* WhirlyGlobe.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E396282027AF59F2005D070E /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E396281F27AF59F2005D070E /* DetailsView.swift */; };
@@ -70,6 +73,7 @@
E33A237227A7581A00DD647F /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
E34A2F4727A7878200AD8AEB /* HyperlinkText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperlinkText.swift; sourceTree = "<group>"; };
E34A2F4C27A7DB2200AD8AEB /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
+ E36A5A8927B4C8BB0070DED5 /* iosApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iosApp.entitlements; sourceTree = "<group>"; };
E36DF77927AB740C003C561C /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = "<group>"; };
E36DF77A27AB740C003C561C /* MapViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = "<group>"; };
E38F241427A242870069FC45 /* Inject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Inject.swift; sourceTree = "<group>"; };
@@ -77,6 +81,8 @@
E38F241B27A26DD70069FC45 /* RootViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModel.swift; sourceTree = "<group>"; };
E38F241D27A270D50069FC45 /* UnitsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsView.swift; sourceTree = "<group>"; };
E38F241F27A27B550069FC45 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
+ E392BE1627B77B7E002698F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ E392BE1827B791F0002698F3 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = WhirlyGlobe.xcframework; sourceTree = "<group>"; };
E396281F27AF59F2005D070E /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
E396282327AFBD3D005D070E /* UnitInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInformationView.swift; sourceTree = "<group>"; };
@@ -93,6 +99,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ E36A5A8627B4BFC40070DED5 /* FirebaseMessaging in Frameworks */,
E33A236A27A6898700DD647F /* SwiftUIX in Frameworks */,
E396281D27AF5723005D070E /* WhirlyGlobe.xcframework in Frameworks */,
);
@@ -129,6 +136,8 @@
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
+ E392BE1827B791F0002698F3 /* GoogleService-Info.plist */,
+ E36A5A8927B4C8BB0070DED5 /* iosApp.entitlements */,
E34A2F4C27A7DB2200AD8AEB /* Localizable.strings */,
E33A235E27A4FD1C00DD647F /* Map */,
E35A078427AB615F00F24D71 /* Details */,
@@ -139,6 +148,7 @@
E3E77EE0279D43B400150070 /* Session */,
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
+ E392BE1627B77B7E002698F3 /* AppDelegate.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
);
path = iosApp;
@@ -262,6 +272,7 @@
name = iosApp;
packageProductDependencies = (
E33A236927A6898700DD647F /* SwiftUIX */,
+ E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */,
);
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* iosApp.app */;
@@ -295,6 +306,7 @@
mainGroup = 7555FF72242A565900829871;
packageReferences = (
E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */,
+ E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
);
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
@@ -312,6 +324,7 @@
files = (
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
E34A2F4D27A7DB2200AD8AEB /* Localizable.strings in Resources */,
+ E392BE1927B791F0002698F3 /* GoogleService-Info.plist in Resources */,
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
E36DF77C27AB740C003C561C /* MapViewController.xib in Resources */,
);
@@ -357,6 +370,7 @@
E396282827AFBD72005D070E /* UnitCommandsView.swift in Sources */,
E38F241C27A26DD70069FC45 /* RootViewModel.swift in Sources */,
E3385A4F27B0D8A10025311C /* UnitCommandsViewModel.swift in Sources */,
+ E392BE1727B77B7E002698F3 /* AppDelegate.swift in Sources */,
E36DF77B27AB740C003C561C /* MapViewController.swift in Sources */,
E33A237327A7581A00DD647F /* Utils.swift in Sources */,
E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */,
@@ -495,6 +509,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
DEVELOPMENT_TEAM = 358YRZ9P3L;
@@ -514,8 +530,9 @@
"-framework",
shared,
);
- PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.TrackerMap;
+ PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.trackermap.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -528,6 +545,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
DEVELOPMENT_TEAM = 358YRZ9P3L;
@@ -547,8 +566,9 @@
"-framework",
shared,
);
- PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.TrackerMap;
+ PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.trackermap.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -587,6 +607,14 @@
kind = branch;
};
};
+ E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 8.0.0;
+ };
+ };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -595,6 +623,11 @@
package = E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */;
productName = SwiftUIX;
};
+ E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseMessaging;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 9e38855..7032494 100644
--- a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -2,6 +2,114 @@
"object": {
"pins": [
{
+ "package": "abseil",
+ "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "fffc3c2729be5747390ad02d5100291a0d9ad26a",
+ "version": "0.20200225.4"
+ }
+ },
+ {
+ "package": "BoringSSL-GRPC",
+ "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "734a8247442fde37df4364c21f6a0085b6a36728",
+ "version": "0.7.2"
+ }
+ },
+ {
+ "package": "Firebase",
+ "repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git",
+ "state": {
+ "branch": null,
+ "revision": "78f7087fd5d48eb7c36e299f330b6dddccd647b2",
+ "version": "8.12.1"
+ }
+ },
+ {
+ "package": "GoogleAppMeasurement",
+ "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
+ "state": {
+ "branch": null,
+ "revision": "6cc2991c11872510a5314bc112cc7558dd9d046a",
+ "version": "8.12.0"
+ }
+ },
+ {
+ "package": "GoogleDataTransport",
+ "repositoryURL": "https://github.com/google/GoogleDataTransport.git",
+ "state": {
+ "branch": null,
+ "revision": "15ccdfd25ac55b9239b82809531ff26605e7556e",
+ "version": "9.1.2"
+ }
+ },
+ {
+ "package": "GoogleUtilities",
+ "repositoryURL": "https://github.com/google/GoogleUtilities.git",
+ "state": {
+ "branch": null,
+ "revision": "b3bb0c5551fb3f80ca939829639ab5b093edd14f",
+ "version": "7.7.0"
+ }
+ },
+ {
+ "package": "gRPC",
+ "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5",
+ "version": "1.28.4"
+ }
+ },
+ {
+ "package": "GTMSessionFetcher",
+ "repositoryURL": "https://github.com/google/gtm-session-fetcher.git",
+ "state": {
+ "branch": null,
+ "revision": "bc6a19702ac76ac4e488b68148710eb815f9bc56",
+ "version": "1.7.0"
+ }
+ },
+ {
+ "package": "leveldb",
+ "repositoryURL": "https://github.com/firebase/leveldb.git",
+ "state": {
+ "branch": null,
+ "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
+ "version": "1.22.2"
+ }
+ },
+ {
+ "package": "nanopb",
+ "repositoryURL": "https://github.com/firebase/nanopb.git",
+ "state": {
+ "branch": null,
+ "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77",
+ "version": "2.30908.0"
+ }
+ },
+ {
+ "package": "Promises",
+ "repositoryURL": "https://github.com/google/promises.git",
+ "state": {
+ "branch": null,
+ "revision": "611337c330350c9c1823ad6d671e7f936af5ee13",
+ "version": "2.0.0"
+ }
+ },
+ {
+ "package": "SwiftProtobuf",
+ "repositoryURL": "https://github.com/apple/swift-protobuf.git",
+ "state": {
+ "branch": null,
+ "revision": "7e2c5f3cbbeea68e004915e3a8961e20bd11d824",
+ "version": "1.18.0"
+ }
+ },
+ {
"package": "SwiftUIX",
"repositoryURL": "https://github.com/ivan-avalos/SwiftUIX",
"state": {
diff --git a/iosApp/iosApp/AppDelegate.swift b/iosApp/iosApp/AppDelegate.swift
new file mode 100644
index 0000000..ebe88df
--- /dev/null
+++ b/iosApp/iosApp/AppDelegate.swift
@@ -0,0 +1,59 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import UIKit
+import Firebase
+import FirebaseMessaging
+
+class AppDelegate: NSObject, UIApplicationDelegate {
+ func applicationDidFinishLaunching(_ application: UIApplication) {
+ FirebaseApp.configure()
+ Messaging.messaging().delegate = self
+
+ UNUserNotificationCenter.current().delegate = self
+ let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
+ UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { _, _ in }
+
+ application.registerForRemoteNotifications()
+ }
+
+ func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
+ print(userInfo)
+ return UIBackgroundFetchResult.newData
+ }
+}
+
+extension AppDelegate: UNUserNotificationCenterDelegate {
+ func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
+ let userInfo = notification.request.content.userInfo
+ print(userInfo)
+ return [.banner, .badge, .sound]
+ }
+
+ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
+ let userInfo = response.notification.request.content.userInfo
+ print(userInfo)
+ }
+}
+
+extension AppDelegate: MessagingDelegate {
+ func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
+ print ("didReceiveRegistrationToken fcmToken:\(String(describing: fcmToken))")
+ UserDefaults.standard.set(fcmToken, forKey: "fcmtoken")
+ }
+}
diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist
index 237f735..bf9db74 100644
--- a/iosApp/iosApp/Info.plist
+++ b/iosApp/iosApp/Info.plist
@@ -4,6 +4,10 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>UIBackgroundModes</key>
+ <array>
+ <string>remote-notification</string>
+ </array>
<key>CFBundleDisplayName</key>
<string>TrackerMap</string>
<key>CFBundleExecutable</key>
diff --git a/iosApp/iosApp/Session/RootView.swift b/iosApp/iosApp/Session/RootView.swift
index 9f2e589..bc8a7d1 100644
--- a/iosApp/iosApp/Session/RootView.swift
+++ b/iosApp/iosApp/Session/RootView.swift
@@ -46,6 +46,12 @@ struct LoginContentView: View {
let onLogin: (SessionBody) -> Void
+ func getFcmToken() -> String? {
+ let token = UserDefaults.standard.string(forKey: "fcmtoken")
+ print("FCM token is \(String(describing: token))")
+ return token
+ }
+
var body: some View {
VStack {
Spacer()
@@ -60,7 +66,7 @@ struct LoginContentView: View {
self.onLogin(SessionBody(url: server,
email: username,
password: password,
- fcmToken: nil))
+ fcmToken: getFcmToken()))
}) {
Text("login")
.font(.system(size: 18))
@@ -74,6 +80,8 @@ struct LoginContentView: View {
}
}
+// Source: https://github.com/niochat/nio
+
struct LoginTitleView: View {
var body: some View {
return VStack {
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
index 338c06b..291f2cd 100644
--- a/iosApp/iosApp/iOSApp.swift
+++ b/iosApp/iosApp/iOSApp.swift
@@ -21,6 +21,7 @@ import shared
@main
struct iOSApp: App {
+ @UIApplicationDelegateAdaptor var delegate: AppDelegate
init() {
/* Dependency injections */
diff --git a/iosApp/iosApp/iosApp.entitlements b/iosApp/iosApp/iosApp.entitlements
new file mode 100644
index 0000000..903def2
--- /dev/null
+++ b/iosApp/iosApp/iosApp.entitlements
@@ -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>