commit 03c2d35fbbcc2240a7f0890834159b299a74263e Author: Akhilesh Date: Mon Feb 10 20:56:00 2025 +0530 first commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..bddaf15 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/next-steps.html b/next-steps.html new file mode 100644 index 0000000..c3f7ac2 --- /dev/null +++ b/next-steps.html @@ -0,0 +1,7 @@ + + + + + diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..1293aee Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..f4f91f1 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,92 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ +/Podfile.lock +/Pods diff --git a/src/CheckoutPaymentViewController.swift b/src/CheckoutPaymentViewController.swift new file mode 100644 index 0000000..04094c4 --- /dev/null +++ b/src/CheckoutPaymentViewController.swift @@ -0,0 +1,39 @@ +import UIKit +import WebKit + +class CheckoutPaymentViewController: UIViewController, WKNavigationDelegate { + +var checkoutUrl: String? // Razorpay checkout URL + +var wkWebView: WKWebView! + +override func viewDidLoad() { +super.viewDidLoad() + +// Initialize WebView +wkWebView = WKWebView(frame: self.view.frame) +wkWebView.navigationDelegate = self +self.view.addSubview(wkWebView) + +self.loadWebPage() +} + +func loadWebPage() { +guard let urlString = self.checkoutUrl else { return } +guard let url = URL(string: urlString) else { return } +self.wkWebView.load(URLRequest(url: url)) +} + +// Handle Payment Success or Failure (Optional) +func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { +if let url = navigationAction.request.url?.absoluteString { +if url.contains("success") { +print("Payment Successful") +self.dismiss(animated: true, completion: nil) // Dismiss ViewController on Success +} else if url.contains("failure") { +print("Payment Failed") +} +} +decisionHandler(.allow) +} +} diff --git a/src/GoogleService-Info.plist b/src/GoogleService-Info.plist new file mode 100644 index 0000000..6f1a2a6 --- /dev/null +++ b/src/GoogleService-Info.plist @@ -0,0 +1,38 @@ + + + + + CLIENT_ID + 9350938798-9pjd1etaka84smk519q61iclr52iu64s.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.9350938798-9pjd1etaka84smk519q61iclr52iu64s + ANDROID_CLIENT_ID + 9350938798-1nmut59vc84ap49t076qine91qpsetal.apps.googleusercontent.com + API_KEY + AIzaSyAFHcM26WF_WlaVjgN0AO_LfHKeluNU4vM + GCM_SENDER_ID + 9350938798 + PLIST_VERSION + 1 + BUNDLE_ID + com.nivesh.app + PROJECT_ID + firebase-nivesh + STORAGE_BUCKET + firebase-nivesh.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:9350938798:ios:e85e4205437e211450ed3f + DATABASE_URL + https://fir-nivesh.firebaseio.com + + \ No newline at end of file diff --git a/src/LICENSE b/src/LICENSE new file mode 100644 index 0000000..f50ef62 --- /dev/null +++ b/src/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/src/Nivesh.xcodeproj/project.pbxproj b/src/Nivesh.xcodeproj/project.pbxproj new file mode 100644 index 0000000..707b2a3 --- /dev/null +++ b/src/Nivesh.xcodeproj/project.pbxproj @@ -0,0 +1,507 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1E01BF082D50AB030044ED2D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1E01BF072D50AB030044ED2D /* GoogleService-Info.plist */; }; + 1EBE67732D50CF2300F6C6D0 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67722D50CF2300F6C6D0 /* FirebaseAnalytics */; }; + 1EBE67752D50CF2300F6C6D0 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67742D50CF2300F6C6D0 /* FirebaseAppCheck */; }; + 1EBE67772D50CF2300F6C6D0 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67762D50CF2300F6C6D0 /* FirebaseAuth */; }; + 1EBE67792D50CF2300F6C6D0 /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67782D50CF2300F6C6D0 /* FirebaseCore */; }; + 1EBE677B2D50CF2300F6C6D0 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE677A2D50CF2300F6C6D0 /* FirebaseCrashlytics */; }; + 1EBE677D2D50CF2300F6C6D0 /* FirebaseDynamicLinks in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE677C2D50CF2300F6C6D0 /* FirebaseDynamicLinks */; }; + 1EBE677F2D50CF2300F6C6D0 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE677E2D50CF2300F6C6D0 /* FirebaseMessaging */; }; + 1EBE67812D50CF2300F6C6D0 /* FirebasePerformance in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67802D50CF2300F6C6D0 /* FirebasePerformance */; }; + 1EBE67852D54952900F6C6D0 /* BranchSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 1EBE67842D54952900F6C6D0 /* BranchSDK */; }; + 1EBE67882D54958E00F6C6D0 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EBE67872D54958E00F6C6D0 /* CoreServices.framework */; }; + 1EBE678A2D5495A900F6C6D0 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EBE67892D5495A900F6C6D0 /* SystemConfiguration.framework */; }; + 1EBE678C2D5495B900F6C6D0 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EBE678B2D5495B900F6C6D0 /* WebKit.framework */; }; + 1EBE678E2D5495D000F6C6D0 /* CoreSpotlight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EBE678D2D5495D000F6C6D0 /* CoreSpotlight.framework */; }; + 595F23A525CEFBFE0053416C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F239A25CEFBFD0053416C /* Settings.swift */; }; + 595F23A625CEFBFE0053416C /* Entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 595F239B25CEFBFD0053416C /* Entitlements */; }; + 595F23A725CEFBFE0053416C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 595F239C25CEFBFD0053416C /* Assets.xcassets */; }; + 595F23A825CEFBFE0053416C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F239D25CEFBFD0053416C /* SceneDelegate.swift */; }; + 595F23AA25CEFBFE0053416C /* PushNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F239F25CEFBFE0053416C /* PushNotifications.swift */; }; + 595F23AC25CEFBFE0053416C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F23A125CEFBFE0053416C /* ViewController.swift */; }; + 595F23AD25CEFBFE0053416C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F23A225CEFBFE0053416C /* AppDelegate.swift */; }; + 595F23AE25CEFBFE0053416C /* Printer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F23A325CEFBFE0053416C /* Printer.swift */; }; + 595F23AF25CEFBFE0053416C /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F23A425CEFBFE0053416C /* WebView.swift */; }; + CDC0FE292388222C002C8D56 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDC0FE252388222B002C8D56 /* Main.storyboard */; }; + CDC0FE2A2388222C002C8D56 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDC0FE272388222B002C8D56 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1E01BF072D50AB030044ED2D /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 1EBE67822D54865300F6C6D0 /* NiveshRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = NiveshRelease.entitlements; path = Nivesh/NiveshRelease.entitlements; sourceTree = ""; }; + 1EBE67872D54958E00F6C6D0 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 1EBE67892D5495A900F6C6D0 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 1EBE678B2D5495B900F6C6D0 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 1EBE678D2D5495D000F6C6D0 /* CoreSpotlight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreSpotlight.framework; path = System/Library/Frameworks/CoreSpotlight.framework; sourceTree = SDKROOT; }; + 59333BAA25CFF706003392A4 /* Nivesh.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nivesh.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 595F239A25CEFBFD0053416C /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Settings.swift; path = Nivesh/Settings.swift; sourceTree = ""; }; + 595F239B25CEFBFD0053416C /* Entitlements */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Entitlements; path = Nivesh/Entitlements; sourceTree = ""; }; + 595F239C25CEFBFD0053416C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Nivesh/Assets.xcassets; sourceTree = ""; }; + 595F239D25CEFBFD0053416C /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = Nivesh/SceneDelegate.swift; sourceTree = ""; }; + 595F239F25CEFBFE0053416C /* PushNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PushNotifications.swift; path = Nivesh/PushNotifications.swift; sourceTree = ""; }; + 595F23A025CEFBFE0053416C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Nivesh/Info.plist; sourceTree = ""; }; + 595F23A125CEFBFE0053416C /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = Nivesh/ViewController.swift; sourceTree = ""; }; + 595F23A225CEFBFE0053416C /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Nivesh/AppDelegate.swift; sourceTree = ""; }; + 595F23A325CEFBFE0053416C /* Printer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Printer.swift; path = Nivesh/Printer.swift; sourceTree = ""; }; + 595F23A425CEFBFE0053416C /* WebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebView.swift; path = Nivesh/WebView.swift; sourceTree = ""; }; + CDC0FE262388222B002C8D56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Nivesh/Base.lproj/Main.storyboard; sourceTree = ""; }; + CDC0FE282388222B002C8D56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Nivesh/Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + CD89F886237E9D9200C436A1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1EBE67852D54952900F6C6D0 /* BranchSDK in Frameworks */, + 1EBE67882D54958E00F6C6D0 /* CoreServices.framework in Frameworks */, + 1EBE678A2D5495A900F6C6D0 /* SystemConfiguration.framework in Frameworks */, + 1EBE678C2D5495B900F6C6D0 /* WebKit.framework in Frameworks */, + 1EBE678E2D5495D000F6C6D0 /* CoreSpotlight.framework in Frameworks */, + 1EBE677F2D50CF2300F6C6D0 /* FirebaseMessaging in Frameworks */, + 1EBE67732D50CF2300F6C6D0 /* FirebaseAnalytics in Frameworks */, + 1EBE67812D50CF2300F6C6D0 /* FirebasePerformance in Frameworks */, + 1EBE67792D50CF2300F6C6D0 /* FirebaseCore in Frameworks */, + 1EBE67752D50CF2300F6C6D0 /* FirebaseAppCheck in Frameworks */, + 1EBE677B2D50CF2300F6C6D0 /* FirebaseCrashlytics in Frameworks */, + 1EBE677D2D50CF2300F6C6D0 /* FirebaseDynamicLinks in Frameworks */, + 1EBE67772D50CF2300F6C6D0 /* FirebaseAuth in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1EBE67862D54958E00F6C6D0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1EBE678D2D5495D000F6C6D0 /* CoreSpotlight.framework */, + 1EBE678B2D5495B900F6C6D0 /* WebKit.framework */, + 1EBE67892D5495A900F6C6D0 /* SystemConfiguration.framework */, + 1EBE67872D54958E00F6C6D0 /* CoreServices.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 30FCACC6A7BF53CD6D9CF6C0 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + path = Pods; + sourceTree = ""; + }; + CD89F880237E9D9200C436A1 = { + isa = PBXGroup; + children = ( + 1EBE67822D54865300F6C6D0 /* NiveshRelease.entitlements */, + 595F23A225CEFBFE0053416C /* AppDelegate.swift */, + 595F239C25CEFBFD0053416C /* Assets.xcassets */, + 595F239B25CEFBFD0053416C /* Entitlements */, + 595F23A025CEFBFE0053416C /* Info.plist */, + 1E01BF072D50AB030044ED2D /* GoogleService-Info.plist */, + 595F23A325CEFBFE0053416C /* Printer.swift */, + 595F239F25CEFBFE0053416C /* PushNotifications.swift */, + 595F239D25CEFBFD0053416C /* SceneDelegate.swift */, + 595F239A25CEFBFD0053416C /* Settings.swift */, + 595F23A125CEFBFE0053416C /* ViewController.swift */, + CDC0FE272388222B002C8D56 /* LaunchScreen.storyboard */, + CDC0FE252388222B002C8D56 /* Main.storyboard */, + 595F23A425CEFBFE0053416C /* WebView.swift */, + 30FCACC6A7BF53CD6D9CF6C0 /* Pods */, + 59333BAA25CFF706003392A4 /* Nivesh.app */, + 1EBE67862D54958E00F6C6D0 /* Frameworks */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CD89F888237E9D9200C436A1 /* Nivesh */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD89F89D237E9D9300C436A1 /* Build configuration list for PBXNativeTarget "Nivesh" */; + buildPhases = ( + CD89F885237E9D9200C436A1 /* Sources */, + CD89F886237E9D9200C436A1 /* Frameworks */, + CD89F887237E9D9200C436A1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Nivesh; + productName = Nivesh; + productReference = 59333BAA25CFF706003392A4 /* Nivesh.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CD89F881237E9D9200C436A1 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1120; + LastUpgradeCheck = 1620; + ORGANIZATIONNAME = ""; + TargetAttributes = { + CD89F888237E9D9200C436A1 = { + CreatedOnToolsVersion = 11.2.1; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = CD89F884237E9D9200C436A1 /* Build configuration list for PBXProject "Nivesh" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CD89F880237E9D9200C436A1; + packageReferences = ( + 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + 1EBE67832D54952900F6C6D0 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */, + ); + productRefGroup = CD89F880237E9D9200C436A1; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CD89F888237E9D9200C436A1 /* Nivesh */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CD89F887237E9D9200C436A1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 595F23A625CEFBFE0053416C /* Entitlements in Resources */, + CDC0FE292388222C002C8D56 /* Main.storyboard in Resources */, + 1E01BF082D50AB030044ED2D /* GoogleService-Info.plist in Resources */, + CDC0FE2A2388222C002C8D56 /* LaunchScreen.storyboard in Resources */, + 595F23A725CEFBFE0053416C /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + CD89F885237E9D9200C436A1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 595F23AD25CEFBFE0053416C /* AppDelegate.swift in Sources */, + 595F23A825CEFBFE0053416C /* SceneDelegate.swift in Sources */, + 595F23A525CEFBFE0053416C /* Settings.swift in Sources */, + 595F23AE25CEFBFE0053416C /* Printer.swift in Sources */, + 595F23AC25CEFBFE0053416C /* ViewController.swift in Sources */, + 595F23AA25CEFBFE0053416C /* PushNotifications.swift in Sources */, + 595F23AF25CEFBFE0053416C /* WebView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + CDC0FE252388222B002C8D56 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CDC0FE262388222B002C8D56 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + CDC0FE272388222B002C8D56 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CDC0FE282388222B002C8D56 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + CD89F89B237E9D9300C436A1 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = 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 = 15.0; + 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"; + TARGETED_DEVICE_FAMILY = "1,2,6"; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + }; + name = Debug; + }; + CD89F89C237E9D9300C436A1 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = 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 = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2,6"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + }; + name = Release; + }; + CD89F89E237E9D9300C436A1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = Nivesh/Entitlements/Entitlements.plist; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = 892H6H36S9; + INFOPLIST_FILE = Nivesh/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.1; + PRODUCT_BUNDLE_IDENTIFIER = com.nivesh.app; + PRODUCT_NAME = Nivesh; + PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,6"; + }; + name = Debug; + }; + CD89F89F237E9D9300C436A1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = Nivesh/NiveshRelease.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = 892H6H36S9; + INFOPLIST_FILE = Nivesh/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.1; + PRODUCT_BUNDLE_IDENTIFIER = com.nivesh.app; + PRODUCT_NAME = Nivesh; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Osize"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,6"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CD89F884237E9D9200C436A1 /* Build configuration list for PBXProject "Nivesh" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD89F89B237E9D9300C436A1 /* Debug */, + CD89F89C237E9D9300C436A1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CD89F89D237E9D9300C436A1 /* Build configuration list for PBXNativeTarget "Nivesh" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD89F89E237E9D9300C436A1 /* Debug */, + CD89F89F237E9D9300C436A1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 11.7.0; + }; + }; + 1EBE67832D54952900F6C6D0 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/BranchMetrics/ios-branch-sdk-spm"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.8.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 1EBE67722D50CF2300F6C6D0 /* FirebaseAnalytics */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalytics; + }; + 1EBE67742D50CF2300F6C6D0 /* FirebaseAppCheck */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; + }; + 1EBE67762D50CF2300F6C6D0 /* FirebaseAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; + }; + 1EBE67782D50CF2300F6C6D0 /* FirebaseCore */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCore; + }; + 1EBE677A2D50CF2300F6C6D0 /* FirebaseCrashlytics */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCrashlytics; + }; + 1EBE677C2D50CF2300F6C6D0 /* FirebaseDynamicLinks */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseDynamicLinks; + }; + 1EBE677E2D50CF2300F6C6D0 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + 1EBE67802D50CF2300F6C6D0 /* FirebasePerformance */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67712D50CF2300F6C6D0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebasePerformance; + }; + 1EBE67842D54952900F6C6D0 /* BranchSDK */ = { + isa = XCSwiftPackageProductDependency; + package = 1EBE67832D54952900F6C6D0 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */; + productName = BranchSDK; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = CD89F881237E9D9200C436A1 /* Project object */; +} diff --git a/src/Nivesh.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/Nivesh.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..101270b --- /dev/null +++ b/src/Nivesh.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..fc6bf80 --- /dev/null +++ b/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..af0309c --- /dev/null +++ b/src/Nivesh.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/src/Nivesh.xcodeproj/xcshareddata/xcschemes/Nivesh.xcscheme b/src/Nivesh.xcodeproj/xcshareddata/xcschemes/Nivesh.xcscheme new file mode 100644 index 0000000..1c7b6d6 --- /dev/null +++ b/src/Nivesh.xcodeproj/xcshareddata/xcschemes/Nivesh.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Nivesh.xcworkspace/contents.xcworkspacedata b/src/Nivesh.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..15868b8 --- /dev/null +++ b/src/Nivesh.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Nivesh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/Nivesh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..fc6bf80 --- /dev/null +++ b/src/Nivesh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/Nivesh.xcworkspace/xcshareddata/swiftpm/Package.resolved b/src/Nivesh.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..3049ffa --- /dev/null +++ b/src/Nivesh.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,132 @@ +{ + "originHash" : "d3fa15d926fa0f697cb981b51acbaff616acb7eb437695719dedfca1f38b248c", + "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "194a6706acbd25e4ef639bcaddea16e8758a3e27", + "version" : "1.2024011602.0" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "61b85103a1aeed8218f17c794687781505fbbef5", + "version" : "11.2.0" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "0d885d28250fb1196b614bc9455079b75c531f72", + "version" : "11.7.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "be0881ff728eca210ccb628092af400c086abda3", + "version" : "11.7.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "617af071af9aa1d6a091d59a202910ac482128f9", + "version" : "10.1.0" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "53156c7ec267db846e6b64c9f4c4e31ba4cf75eb", + "version" : "8.0.2" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "f56d8fc3162de9a498377c7b6cea43431f4f5083", + "version" : "1.65.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "3cdb78efb79b4a5383c3911488d8025bfc545b5e", + "version" : "4.3.0" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", + "version" : "100.0.0" + } + }, + { + "identity" : "ios-branch-sdk-spm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", + "state" : { + "revision" : "37d0fb8ff04098807957b1d387812ed8f96fbdc7", + "version" : "3.8.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1", + "version" : "1.22.5" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1", + "version" : "2.30910.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version" : "2.4.0" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "ebc7251dd5b37f627c93698e4374084d98409633", + "version" : "1.28.2" + } + } + ], + "version" : 3 +} diff --git a/src/Nivesh/.DS_Store b/src/Nivesh/.DS_Store new file mode 100644 index 0000000..82dac0a Binary files /dev/null and b/src/Nivesh/.DS_Store differ diff --git a/src/Nivesh/AppDelegate.swift b/src/Nivesh/AppDelegate.swift new file mode 100644 index 0000000..96585e2 --- /dev/null +++ b/src/Nivesh/AppDelegate.swift @@ -0,0 +1,151 @@ +import UIKit +import FirebaseCore +import FirebaseMessaging +import UserNotifications +import BranchSDK + + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window : UIWindow? + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + +// TODO: if we're using Firebase, uncomment next string + FirebaseApp.configure() + + // [START set_messaging_delegate] + Messaging.messaging().delegate = self + // [END set_messaging_delegate] + // Register for remote notifications. This shows a permission dialog on first run, to + // show the dialog at a more appropriate time move this registration accordingly. + // [START register_for_notifications] + + UNUserNotificationCenter.current().delegate = self + + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] + UNUserNotificationCenter.current().requestAuthorization( + options: authOptions, + completionHandler: {_, _ in }) + +// TODO: if we're using Firebase, uncomment next string + application.registerForRemoteNotifications() + + // [END register_for_notifications] + + // This version of `initSession` includes the source UIScene in the callback + BranchScene.shared().initSession(launchOptions: launchOptions, registerDeepLinkHandler: { (params, error, scene) in + + }) + return true + } + + + // [START receive_message] + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) { + // If you are receiving a notification message while your app is in the background, + // this callback will not be fired till the user taps on the notification launching the application. + // With swizzling disabled you must let Messaging know about the message, for Analytics + Messaging.messaging().appDidReceiveMessage(userInfo) + // Print message ID. + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID 1: \(messageID)") + } + + // Print full message. + print("push userInfo 1:", userInfo) + sendPushToWebView(userInfo: userInfo) + } + + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], + fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + // If you are receiving a notification message while your app is in the background, + // this callback will not be fired till the user taps on the notification launching the application. + // With swizzling disabled you must let Messaging know about the message, for Analytics + Messaging.messaging().appDidReceiveMessage(userInfo) + // Print message ID. + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID 2: \(messageID)") + } + + // Print full message. ** + print("push userInfo 2:", userInfo) + sendPushToWebView(userInfo: userInfo) + + completionHandler(UIBackgroundFetchResult.newData) + } + + // [END receive_message] + func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { + print("Unable to register for remote notifications: \(error.localizedDescription)") + } + + // This function is added here only for debugging purposes, and can be removed if swizzling is enabled. + // If swizzling is disabled then this function must be implemented so that the APNs token can be paired to + // the FCM registration token. + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + print("APNs token retrieved: \(deviceToken)") + + // With swizzling disabled you must set the APNs token here. + Messaging.messaging().apnsToken = deviceToken + } + } + + // [START ios_10_message_handling] + extension AppDelegate : UNUserNotificationCenterDelegate { + + func userNotificationCenter(_ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + let userInfo = notification.request.content.userInfo + + // With swizzling disabled you must let Messaging know about the message, for Analytics + Messaging.messaging().appDidReceiveMessage(userInfo) + // Print message ID. + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: 3 \(messageID)") + } + + // Print full message. + print("push userInfo 3:", userInfo) + sendPushToWebView(userInfo: userInfo) + + // Change this to your preferred presentation option + completionHandler([[.banner, .list, .sound]]) + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void) { + let userInfo = response.notification.request.content.userInfo + // Print message ID. + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID 4: \(messageID)") + } + + // With swizzling disabled you must let Messaging know about the message, for Analytics + Messaging.messaging().appDidReceiveMessage(userInfo) + // Print full message. + print("push userInfo 4:", userInfo) + sendPushToWebView(userInfo: userInfo) + + completionHandler() + } + } + // [END ios_10_message_handling] + + extension AppDelegate : MessagingDelegate { + // [START refresh_token] + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + print("Firebase registration token: \(String(describing: fcmToken))") + + let dataDict:[String: String] = ["token": fcmToken ?? ""] + NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict) + handleFCMToken() + // TODO: If necessary send token to application server. + // Note: This callback is fired at each app startup and whenever a new token is generated. + } + // [END refresh_token] + } diff --git a/src/Nivesh/Assets.xcassets/.DS_Store b/src/Nivesh/Assets.xcassets/.DS_Store new file mode 100644 index 0000000..fc87c19 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/.DS_Store differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/.DS_Store b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/.DS_Store new file mode 100644 index 0000000..35f1ba6 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/.DS_Store differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/100.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 0000000..0c8038c Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/102.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/102.png new file mode 100644 index 0000000..ca640f3 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/102.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/1024.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000..5cab1dc Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/108.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/108.png new file mode 100644 index 0000000..85ca582 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/108.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/114.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/114.png new file mode 100644 index 0000000..70f623e Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/114.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/120.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000..f158f64 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/120.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/128.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/128.png new file mode 100644 index 0000000..3f7d513 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/144.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 0000000..8088225 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/152.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 0000000..373f295 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/16.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/16.png new file mode 100644 index 0000000..08483d4 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/167.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000..5f2829e Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/172.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/172.png new file mode 100644 index 0000000..b6964f3 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/172.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/180.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000..b533a84 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/192.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/192.png new file mode 100644 index 0000000..4490cef Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/192.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/196.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/196.png new file mode 100644 index 0000000..717078a Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/196.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/20.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 0000000..4bf686e Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/216.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/216.png new file mode 100644 index 0000000..c41e8ae Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/216.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/234.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/234.png new file mode 100644 index 0000000..00848d0 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/234.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/256.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/256.png new file mode 100644 index 0000000..0c0d93f Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/258.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/258.png new file mode 100644 index 0000000..a9ed532 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/258.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/29.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000..93ab411 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/32.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/32.png new file mode 100644 index 0000000..8c38054 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/40.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000..066d334 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/48.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/48.png new file mode 100644 index 0000000..33baf41 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/48.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/50.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 0000000..d65e446 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/512.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/512.png new file mode 100644 index 0000000..6600d49 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/55.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/55.png new file mode 100644 index 0000000..a88ffa3 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/55.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/57.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 0000000..9796cad Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/57.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/58.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000..a77ebf8 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/60.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000..db64441 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/64.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/64.png new file mode 100644 index 0000000..09a1079 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/66.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/66.png new file mode 100644 index 0000000..c2594bb Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/66.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/72.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/72.png new file mode 100644 index 0000000..62f32b7 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/76.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000..d344f44 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/80.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 0000000..73af021 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/87.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 0000000..39e9bbd Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/88.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/88.png new file mode 100644 index 0000000..d120937 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/88.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/92.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/92.png new file mode 100644 index 0000000..5ee22c7 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/92.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png new file mode 100644 index 0000000..df9fde1 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png new file mode 100644 index 0000000..fe766c3 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png new file mode 100644 index 0000000..9800c68 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png new file mode 100644 index 0000000..d8985dd Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png new file mode 100644 index 0000000..fe766c3 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png new file mode 100644 index 0000000..4727035 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png new file mode 100644 index 0000000..d8985dd Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png new file mode 100644 index 0000000..db14b12 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png new file mode 100644 index 0000000..4727035 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png new file mode 100644 index 0000000..c622766 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9744e77 --- /dev/null +++ b/src/Nivesh/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,224 @@ +{ + "images" : [ + { + "filename" : "40.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "60.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "29.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "58.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "87.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "80.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "120.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "57.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "57x57" + }, + { + "filename" : "114.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "57x57" + }, + { + "filename" : "120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "40.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "58.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "40.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "80.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "50.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "50x50" + }, + { + "filename" : "100.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "50x50" + }, + { + "filename" : "72.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "72x72" + }, + { + "filename" : "144.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "72x72" + }, + { + "filename" : "76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "152.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "167.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "filename" : "AppIcon-16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "AppIcon-16@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "AppIcon-32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "AppIcon-32@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "AppIcon-128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "AppIcon-128@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "AppIcon-256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "AppIcon-256@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "AppIcon-512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "AppIcon-512@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + }, + { + "filename" : "192.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "192x192" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/Nivesh/Assets.xcassets/Contents.json b/src/Nivesh/Assets.xcassets/Contents.json new file mode 100644 index 0000000..22f4cd6 --- /dev/null +++ b/src/Nivesh/Assets.xcassets/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "compression-type" : "gpu-optimized-smallest" + } +} diff --git a/src/Nivesh/Assets.xcassets/n-logo.imageset/1080.png b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080.png new file mode 100644 index 0000000..089ed94 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080.png differ diff --git a/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@2x.png b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@2x.png new file mode 100644 index 0000000..5951131 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@3x.png b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@3x.png new file mode 100644 index 0000000..829885b Binary files /dev/null and b/src/Nivesh/Assets.xcassets/n-logo.imageset/1080@3x.png differ diff --git a/src/Nivesh/Assets.xcassets/n-logo.imageset/Contents.json b/src/Nivesh/Assets.xcassets/n-logo.imageset/Contents.json new file mode 100644 index 0000000..eba6bf0 --- /dev/null +++ b/src/Nivesh/Assets.xcassets/n-logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "1080.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "1080@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "1080@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/Contents.json b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/Contents.json new file mode 100644 index 0000000..eea3c2c --- /dev/null +++ b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "splash-screen-logo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "splash-screen-logo@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "splash-screen-logo@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo.png b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo.png new file mode 100644 index 0000000..3542ef1 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo.png differ diff --git a/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@2x.png b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@2x.png new file mode 100644 index 0000000..a6243a6 Binary files /dev/null and b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@2x.png differ diff --git a/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@3x.png b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@3x.png new file mode 100644 index 0000000..835bd7a Binary files /dev/null and b/src/Nivesh/Assets.xcassets/splash-screen-logo.imageset/splash-screen-logo@3x.png differ diff --git a/src/Nivesh/Base.lproj/LaunchScreen.storyboard b/src/Nivesh/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..d4e3f63 --- /dev/null +++ b/src/Nivesh/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Nivesh/Base.lproj/Main.storyboard b/src/Nivesh/Base.lproj/Main.storyboard new file mode 100644 index 0000000..3db982a --- /dev/null +++ b/src/Nivesh/Base.lproj/Main.storyboard @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Nivesh/Entitlements/.gitignore b/src/Nivesh/Entitlements/.gitignore new file mode 100644 index 0000000..53b4c63 --- /dev/null +++ b/src/Nivesh/Entitlements/.gitignore @@ -0,0 +1 @@ +/GoogleService-Info.plist diff --git a/src/Nivesh/Entitlements/Entitlements.plist b/src/Nivesh/Entitlements/Entitlements.plist new file mode 100644 index 0000000..1371916 --- /dev/null +++ b/src/Nivesh/Entitlements/Entitlements.plist @@ -0,0 +1,27 @@ + + + + + aps-environment + production + com.apple.developer.associated-domains + + applinks:app.nivesh.com + webcredentials:app.nivesh.com + + com.apple.security.app-sandbox + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.personal-information.location + + com.apple.security.print + + + diff --git a/src/Nivesh/Info.plist b/src/Nivesh/Info.plist new file mode 100644 index 0000000..e7717d7 --- /dev/null +++ b/src/Nivesh/Info.plist @@ -0,0 +1,124 @@ + + + + + BGTaskSchedulerPermittedIdentifiers + + $(PRODUCT_BUNDLE_IDENTIFIER) + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Nivesh + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.nivesh.app + CFBundleURLSchemes + + app + + + + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSCameraUsageDescription + App needs to capture user document for KYC mandated by Indian regulation (SEBI) + NSLocationWhenInUseUsageDescription + Track current location by user request + NSMicrophoneUsageDescription + Capture Audio by user request + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIBackgroundModes + + processing + remote-notification + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarStyle + UIStatusBarStyleDefault + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + WKAppBoundDomains + + sandbox.nivesh.com + + branch_key + + live + key_live_ihFWcIYhk9JEbG6TR0dOSbkoDydh2HKF + + branch_universal_link_domains + + Item 0 + nivesh.app.link + Item 1 + nivesh-alternate.app.link + + + diff --git a/src/Nivesh/NiveshRelease.entitlements b/src/Nivesh/NiveshRelease.entitlements new file mode 100644 index 0000000..4da5192 --- /dev/null +++ b/src/Nivesh/NiveshRelease.entitlements @@ -0,0 +1,29 @@ + + + + + aps-environment + production + com.apple.developer.associated-domains + + applinks:app.nivesh.com + webcredentials:app.nivesh.com + nivesh.app.link + nivesh-alternate.app.link + + com.apple.security.app-sandbox + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.personal-information.location + + com.apple.security.print + + + diff --git a/src/Nivesh/Printer.swift b/src/Nivesh/Printer.swift new file mode 100644 index 0000000..fff7db5 --- /dev/null +++ b/src/Nivesh/Printer.swift @@ -0,0 +1,20 @@ +import UIKit +import WebKit + +func printView(webView: WKWebView){ + let printController = UIPrintInteractionController.shared + + let printInfo = UIPrintInfo(dictionary:nil) + printInfo.outputType = UIPrintInfo.OutputType.general + printInfo.jobName = (webView.url?.absoluteString)! + printInfo.duplex = UIPrintInfo.Duplex.none + printInfo.orientation = UIPrintInfo.Orientation.portrait + + printController.printPageRenderer = UIPrintPageRenderer() + + printController.printPageRenderer?.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0) + + printController.printInfo = printInfo + printController.showsNumberOfCopies = true + printController.present(animated: true) +} diff --git a/src/Nivesh/PushNotifications.swift b/src/Nivesh/PushNotifications.swift new file mode 100644 index 0000000..e73bd67 --- /dev/null +++ b/src/Nivesh/PushNotifications.swift @@ -0,0 +1,173 @@ +import WebKit +import FirebaseMessaging + +class SubscribeMessage { + var topic = "" + var eventValue = "" + var unsubscribe = false + struct Keys { + static var TOPIC = "topic" + static var UNSUBSCRIBE = "unsubscribe" + static var EVENTVALUE = "eventValue" + } + convenience init(dict: Dictionary) { + self.init() + if let topic = dict[Keys.TOPIC] as? String { + self.topic = topic + } + if let unsubscribe = dict[Keys.UNSUBSCRIBE] as? Bool { + self.unsubscribe = unsubscribe + } + if let eventValue = dict[Keys.EVENTVALUE] as? String { + self.eventValue = eventValue + } + } +} + +func handleSubscribeTouch(message: WKScriptMessage) { + // [START subscribe_topic] + let subscribeMessages = parseSubscribeMessage(message: message) + if (subscribeMessages.count > 0){ + let _message = subscribeMessages[0] + if (_message.unsubscribe) { + Messaging.messaging().unsubscribe(fromTopic: _message.topic) { error in } + } + else { + Messaging.messaging().subscribe(toTopic: _message.topic) { error in } + } + } + + + // [END subscribe_topic] +} + +func parseSubscribeMessage(message: WKScriptMessage) -> [SubscribeMessage] { + var subscribeMessages = [SubscribeMessage]() + if let objStr = message.body as? String { + + let data: Data = objStr.data(using: .utf8)! + do { + let jsObj = try JSONSerialization.jsonObject(with: data, options: .init(rawValue: 0)) + if let jsonObjDict = jsObj as? Dictionary { + let subscribeMessage = SubscribeMessage(dict: jsonObjDict) + subscribeMessages.append(subscribeMessage) + } else if let jsonArr = jsObj as? [Dictionary] { + for jsonObj in jsonArr { + let sMessage = SubscribeMessage(dict: jsonObj) + subscribeMessages.append(sMessage) + } + } + } catch _ { + + } + } + return subscribeMessages +} + +func returnPermissionResult(isGranted: Bool){ + DispatchQueue.main.async(execute: { + if (isGranted){ + Nivesh.webView.evaluateJavaScript("this.dispatchEvent(new CustomEvent('push-permission-request', { detail: 'granted' }))") + } + else { + Nivesh.webView.evaluateJavaScript("this.dispatchEvent(new CustomEvent('push-permission-request', { detail: 'denied' }))") + } + }) +} +func returnPermissionState(state: String){ + DispatchQueue.main.async(execute: { + Nivesh.webView.evaluateJavaScript("this.dispatchEvent(new CustomEvent('push-permission-state', { detail: '\(state)' }))") + }) +} + +func handlePushPermission() { + UNUserNotificationCenter.current().getNotificationSettings () { settings in + switch settings.authorizationStatus { + case .notDetermined: + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] + UNUserNotificationCenter.current().requestAuthorization( + options: authOptions, + completionHandler: { (success, error) in + if error == nil { + if success == true { + returnPermissionResult(isGranted: true) + DispatchQueue.main.async { + UIApplication.shared.registerForRemoteNotifications() + } + } + else { + returnPermissionResult(isGranted: false) + } + } + else { + returnPermissionResult(isGranted: false) + } + } + ) + case .denied: + returnPermissionResult(isGranted: false) + case .authorized, .ephemeral, .provisional: + returnPermissionResult(isGranted: true) + @unknown default: + return; + } + } +} +func handlePushState() { + UNUserNotificationCenter.current().getNotificationSettings () { settings in + switch settings.authorizationStatus { + case .notDetermined: + returnPermissionState(state: "notDetermined") + case .denied: + returnPermissionState(state: "denied") + case .authorized: + returnPermissionState(state: "authorized") + case .ephemeral: + returnPermissionState(state: "ephemeral") + case .provisional: + returnPermissionState(state: "provisional") + @unknown default: + returnPermissionState(state: "unknown") + return; + } + } +} + +func checkViewAndEvaluate(event: String, detail: String) { + if (!Nivesh.webView.isHidden && !Nivesh.webView.isLoading ) { + DispatchQueue.main.async(execute: { + Nivesh.webView.evaluateJavaScript("this.dispatchEvent(new CustomEvent('\(event)', { detail: \(detail) }))") + }) + } + else { + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + checkViewAndEvaluate(event: event, detail: detail) + } + } +} + +func handleFCMToken(){ + DispatchQueue.main.async(execute: { + Messaging.messaging().token { token, error in + if let error = error { + print("Error fetching FCM registration token: \(error)") + checkViewAndEvaluate(event: "push-token", detail: "ERROR GET TOKEN") + } else if let token = token { + print("FCM registration token: \(token)") + checkViewAndEvaluate(event: "push-token", detail: "'\(token)'") + } + } + }) +} + +func sendPushToWebView(userInfo: [AnyHashable: Any]){ + var json = ""; + do { + let jsonData = try JSONSerialization.data(withJSONObject: userInfo) + json = String(data: jsonData, encoding: .utf8)! + } catch { + print("ERROR: userInfo parsing problem") + return + } + checkViewAndEvaluate(event: "push-notification", detail: json) +} diff --git a/src/Nivesh/SceneDelegate.swift b/src/Nivesh/SceneDelegate.swift new file mode 100644 index 0000000..2637dad --- /dev/null +++ b/src/Nivesh/SceneDelegate.swift @@ -0,0 +1,111 @@ +import UIKit + +@available(iOS 13.0, *) +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + // If our app is launched with a universal link, we'll store it in this variable + static var universalLinkToLaunch: URL? = nil; + static var shortcutLinkToLaunch: URL? = nil + + + // This function is called when your app launches. + // Check to see if we were launched via a universal link or a shortcut. + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // See if our app is being launched via universal link. + // If so, store that link so we can navigate to it once our webView is initialized. + for userActivity in connectionOptions.userActivities { + if let universalLink = userActivity.webpageURL { + SceneDelegate.universalLinkToLaunch = universalLink; + break + } + } + + // See if we were launched via shortcut + if let shortcutUrl = connectionOptions.shortcutItem?.type { + SceneDelegate.shortcutLinkToLaunch = URL.init(string: shortcutUrl) + } + + // See if we were launched via scheme URL + if let schemeUrl = connectionOptions.urlContexts.first?.url { + // Convert scheme://url to a https://url + var comps = URLComponents(url: schemeUrl, resolvingAgainstBaseURL: false) + comps?.scheme = "https" + + if let url = comps?.url { + SceneDelegate.universalLinkToLaunch = url; + } + } + } + + // This function is called when our app is already running and the user clicks a custom scheme URL + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + if let scheme = URLContexts.first?.url { + // Convert scheme://url to a https://url and navigate to it + var comps = URLComponents(url: scheme, resolvingAgainstBaseURL: false) + comps?.scheme = "https" + + if let url = comps?.url { + // Handle it inside our web view in a SPA-friendly way. + Nivesh.webView.evaluateJavaScript("location.href = '\(url)'") + } + } + } + + // This function is called when our app is already running and the user clicks a universal link. + func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { + // Handle universal links into our app when the app is already running. + // This allows your PWA to open links to your domain, rather than opening in a browser tab. + // For more info about universal links, see https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app + + // Ensure we're trying to launch a link. + guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let universalLink = userActivity.webpageURL else { + return + } + + // Handle it inside our web view in a SPA-friendly way. + Nivesh.webView.evaluateJavaScript("location.href = '\(universalLink)'") + } + + // This function is called if our app is already loaded and the user activates the app via shortcut + func windowScene(_ windowScene: UIWindowScene, + performActionFor shortcutItem: UIApplicationShortcutItem, + completionHandler: @escaping (Bool) -> Void) { + if let shortcutUrl = URL.init(string: shortcutItem.type) { + Nivesh.webView.evaluateJavaScript("location.href = '\(shortcutUrl)'"); + } + } + + 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. + } + + +} + diff --git a/src/Nivesh/Settings.swift b/src/Nivesh/Settings.swift new file mode 100644 index 0000000..b814c2d --- /dev/null +++ b/src/Nivesh/Settings.swift @@ -0,0 +1,29 @@ +import WebKit + +struct Cookie { + var name: String + var value: String +} + +let gcmMessageIDKey = "00000000000" // update this with actual ID if using Firebase + +// URL for first launch +let rootUrl = URL(string: "https://sandbox.nivesh.com")! + +// allowed origin is for what we are sticking to pwa domain +// This should also appear in Info.plist +let allowedOrigins: [String] = ["sandbox.nivesh.com"] + +// auth origins will open in modal and show toolbar for back into the main origin. +// These should also appear in Info.plist +let authOrigins: [String] = [] +// allowedOrigins + authOrigins <= 10 + +let platformCookie = Cookie(name: "app-platform", value: "iOS App Store") + +// UI options +let displayMode = "standalone" // standalone / fullscreen. +let adaptiveUIStyle = true // iOS 15+ only. Change app theme on the fly to dark/light related to WebView background color. +let overrideStatusBar = false // iOS 13-14 only. if you don't support dark/light system theme. +let statusBarTheme = "dark" // dark / light, related to override option. +let pullToRefresh = true // Enable/disable pull down to refresh page diff --git a/src/Nivesh/ViewController.swift b/src/Nivesh/ViewController.swift new file mode 100644 index 0000000..5dafd66 --- /dev/null +++ b/src/Nivesh/ViewController.swift @@ -0,0 +1,249 @@ +import UIKit +import WebKit + +var webView: WKWebView! = nil + +class ViewController: UIViewController, WKNavigationDelegate, UIDocumentInteractionControllerDelegate { + + var documentController: UIDocumentInteractionController? + func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { + return self + } + + @IBOutlet weak var loadingView: UIView! + @IBOutlet weak var progressView: UIProgressView! + @IBOutlet weak var connectionProblemView: UIImageView! + @IBOutlet weak var webviewView: UIView! + var toolbarView: UIToolbar! + + var htmlIsLoaded = false; + + private var themeObservation: NSKeyValueObservation? + var currentWebViewTheme: UIUserInterfaceStyle = .unspecified + override var preferredStatusBarStyle : UIStatusBarStyle { + if #available(iOS 13, *), overrideStatusBar{ + if #available(iOS 15, *) { + return .default + } else { + return statusBarTheme == "dark" ? .lightContent : .darkContent + } + } + return .default + } + + override func viewDidLoad() { + super.viewDidLoad() + initWebView() + initToolbarView() + loadRootUrl() + + NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification , object: nil) + + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + Nivesh.webView.frame = calcWebviewFrame(webviewView: webviewView, toolbarView: nil) + } + + @objc func keyboardWillHide(_ notification: NSNotification) { + Nivesh.webView.setNeedsLayout() + } + + func initWebView() { + Nivesh.webView = createWebView(container: webviewView, WKSMH: self, WKND: self, NSO: self, VC: self) + webviewView.addSubview(Nivesh.webView); + + Nivesh.webView.uiDelegate = self; + + Nivesh.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) + + if(pullToRefresh){ + let refreshControl = UIRefreshControl() + refreshControl.addTarget(self, action: #selector(refreshWebView(_:)), for: UIControl.Event.valueChanged) + Nivesh.webView.scrollView.addSubview(refreshControl) + Nivesh.webView.scrollView.bounces = true + } + + if #available(iOS 15.0, *), adaptiveUIStyle { + themeObservation = Nivesh.webView.observe(\.underPageBackgroundColor) { [unowned self] webView, _ in + currentWebViewTheme = Nivesh.webView.underPageBackgroundColor.isLight() ?? true ? .light : .dark + self.overrideUIStyle() + } + } + } + + @objc func refreshWebView(_ sender: UIRefreshControl) { + Nivesh.webView?.reload() + sender.endRefreshing() + } + + func createToolbarView() -> UIToolbar{ + let winScene = UIApplication.shared.connectedScenes.first + let windowScene = winScene as! UIWindowScene + var statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 60 + + #if targetEnvironment(macCatalyst) + if (statusBarHeight == 0){ + statusBarHeight = 30 + } + #endif + + let toolbarView = UIToolbar(frame: CGRect(x: 0, y: 0, width: webviewView.frame.width, height: 0)) + toolbarView.sizeToFit() + toolbarView.frame = CGRect(x: 0, y: 0, width: webviewView.frame.width, height: toolbarView.frame.height + statusBarHeight) +// toolbarView.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleWidth] + + let flex = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + let close = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(loadRootUrl)) + toolbarView.setItems([close,flex], animated: true) + + toolbarView.isHidden = true + + return toolbarView + } + + func overrideUIStyle(toDefault: Bool = false) { + if #available(iOS 15.0, *), adaptiveUIStyle { + if (((htmlIsLoaded && !Nivesh.webView.isHidden) || toDefault) && self.currentWebViewTheme != .unspecified) { + UIApplication + .shared + .connectedScenes + .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } + .first { $0.isKeyWindow }?.overrideUserInterfaceStyle = toDefault ? .unspecified : self.currentWebViewTheme; + } + } + } + + func initToolbarView() { + toolbarView = createToolbarView() + + webviewView.addSubview(toolbarView) + } + + @objc func loadRootUrl() { + Nivesh.webView.load(URLRequest(url: SceneDelegate.universalLinkToLaunch ?? SceneDelegate.shortcutLinkToLaunch ?? rootUrl)) + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!){ + htmlIsLoaded = true + + self.setProgress(1.0, true) + self.animateConnectionProblem(false) + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { + Nivesh.webView.isHidden = false + self.loadingView.isHidden = true + + self.setProgress(0.0, false) + + self.overrideUIStyle() + } + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + htmlIsLoaded = false; + + if (error as NSError)._code != (-999) { + self.overrideUIStyle(toDefault: true); + + webView.isHidden = true; + loadingView.isHidden = false; + animateConnectionProblem(true); + + setProgress(0.05, true); + + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + self.setProgress(0.1, true); + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + self.loadRootUrl(); + } + } + } + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + + if (keyPath == #keyPath(WKWebView.estimatedProgress) && + Nivesh.webView.isLoading && + !self.loadingView.isHidden && + !self.htmlIsLoaded) { + var progress = Float(Nivesh.webView.estimatedProgress); + + if (progress >= 0.8) { progress = 1.0; }; + if (progress >= 0.3) { self.animateConnectionProblem(false); } + + self.setProgress(progress, true); + } + } + + func setProgress(_ progress: Float, _ animated: Bool) { + self.progressView.setProgress(progress, animated: animated); + } + + + func animateConnectionProblem(_ show: Bool) { + if (show) { + self.connectionProblemView.isHidden = false; + self.connectionProblemView.alpha = 0 + UIView.animate(withDuration: 0.7, delay: 0, options: [.repeat, .autoreverse], animations: { + self.connectionProblemView.alpha = 1 + }) + } + else { + UIView.animate(withDuration: 0.3, delay: 0, options: [], animations: { + self.connectionProblemView.alpha = 0 // Here you will get the animation you want + }, completion: { _ in + self.connectionProblemView.isHidden = true; + self.connectionProblemView.layer.removeAllAnimations(); + }) + } + } + + deinit { + Nivesh.webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress)) + } +} + + +extension UIColor { + // Check if the color is light or dark, as defined by the injected lightness threshold. + // Some people report that 0.7 is best. I suggest to find out for yourself. + // A nil value is returned if the lightness couldn't be determined. + func isLight(threshold: Float = 0.5) -> Bool? { + let originalCGColor = self.cgColor + + // Now we need to convert it to the RGB colorspace. UIColor.white / UIColor.black are greyscale and not RGB. + // If you don't do this then you will crash when accessing components index 2 below when evaluating greyscale colors. + let RGBCGColor = originalCGColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil) + guard let components = RGBCGColor?.components else { + return nil + } + guard components.count >= 3 else { + return nil + } + + let brightness = Float(((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000) + return (brightness > threshold) + } +} + +extension ViewController: WKScriptMessageHandler { + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if message.name == "print" { + printView(webView: Nivesh.webView) + } + if message.name == "push-subscribe" { + handleSubscribeTouch(message: message) + } + if message.name == "push-permission-request" { + handlePushPermission() + } + if message.name == "push-permission-state" { + handlePushState() + } + if message.name == "push-token" { + handleFCMToken() + } + } +} diff --git a/src/Nivesh/WebView.swift b/src/Nivesh/WebView.swift new file mode 100644 index 0000000..d2fceb9 --- /dev/null +++ b/src/Nivesh/WebView.swift @@ -0,0 +1,406 @@ +import UIKit +import WebKit +import AuthenticationServices +import SafariServices +import FirebaseMessaging + + +func createWebView(container: UIView, WKSMH: WKScriptMessageHandler, WKND: WKNavigationDelegate, NSO: NSObject, VC: ViewController) -> WKWebView{ + + let config = WKWebViewConfiguration() + let userContentController = WKUserContentController() + + userContentController.add(WKSMH, name: "print") + userContentController.add(WKSMH, name: "push-subscribe") + userContentController.add(WKSMH, name: "push-permission-request") + userContentController.add(WKSMH, name: "push-permission-state") + userContentController.add(WKSMH, name: "push-token") + + config.userContentController = userContentController + + config.limitsNavigationsToAppBoundDomains = false; + config.allowsInlineMediaPlayback = true + config.preferences.javaScriptCanOpenWindowsAutomatically = true + config.preferences.setValue(true, forKey: "standalone") + + let webView = WKWebView(frame: calcWebviewFrame(webviewView: container, toolbarView: nil), configuration: config) + + setCustomCookie(webView: webView) + + webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + webView.isHidden = true; + + webView.navigationDelegate = WKND + + webView.scrollView.bounces = false + webView.scrollView.contentInsetAdjustmentBehavior = .never + webView.allowsBackForwardNavigationGestures = true + + let deviceModel = UIDevice.current.model + let osVersion = UIDevice.current.systemVersion + let deviceID = UIDevice.current.identifierForVendor!.uuidString + let deviceName = UIDevice.current.name + let FCMToken = Messaging.messaging().fcmToken + + webView.configuration.applicationNameForUserAgent = "Safari/604.1" + webView.customUserAgent = "Mozilla/5.0 (\(deviceModel); CPU \(deviceModel) OS \(osVersion.replacingOccurrences(of: ".", with: "_")) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/\(osVersion) Mobile/15E148 Safari/604.1 PWAShell" + + webView.addObserver(NSO, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: NSKeyValueObservingOptions.new, context: nil) + + let localStorageData: [String: Any] = [ + "model": deviceModel, + "systemVersion": osVersion, + "deviceID": deviceID, + "deviceName": deviceName, + "FCMtoken" : FCMToken! + ] + + print("test", localStorageData) + + + + if JSONSerialization.isValidJSONObject(localStorageData), + let data = try? JSONSerialization.data(withJSONObject: localStorageData, options: []), + let value = String(data: data, encoding: .utf8) { + + let _deviceCookie = HTTPCookie(properties: [ + .domain: rootUrl.host!, + .path: "/", + .name: "deviceInfo", + .value: "\(value)", + .secure: "FALSE", + .expires: NSDate(timeIntervalSinceNow: 31556926) + ])! + + webView.configuration.websiteDataStore.httpCookieStore.setCookie(_deviceCookie) + } + + + + #if DEBUG + if #available(iOS 16.4, *) { + webView.isInspectable = true + } + #endif + + return webView +} + +func setAppStoreAsReferrer(contentController: WKUserContentController) { + let scriptSource = "document.referrer = `app-info://platform/ios-store`;" + let script = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true) + contentController.addUserScript(script); +} + +func setCustomCookie(webView: WKWebView) { + + let _platformCookie = HTTPCookie(properties: [ + .domain: rootUrl.host!, + .path: "/", + .name: platformCookie.name, + .value: platformCookie.value, + .secure: "FALSE", + .expires: NSDate(timeIntervalSinceNow: 31556926) + ])! + webView.configuration.websiteDataStore.httpCookieStore.setCookie(_platformCookie) + +} + +func calcWebviewFrame(webviewView: UIView, toolbarView: UIToolbar?) -> CGRect{ + if ((toolbarView) != nil) { + return CGRect(x: 0, y: toolbarView!.frame.height, width: webviewView.frame.width, height: webviewView.frame.height - toolbarView!.frame.height) + } + else { + let winScene = UIApplication.shared.connectedScenes.first + let windowScene = winScene as! UIWindowScene + var statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 0 + + switch displayMode { + case "fullscreen": + #if targetEnvironment(macCatalyst) + if let titlebar = windowScene.titlebar { + titlebar.titleVisibility = .hidden + titlebar.toolbar = nil + } + #endif + return CGRect(x: 0, y: 0, width: webviewView.frame.width, height: webviewView.frame.height) + default: + #if targetEnvironment(macCatalyst) + statusBarHeight = 29 + #endif + let windowHeight = webviewView.frame.height - statusBarHeight + return CGRect(x: 0, y: statusBarHeight, width: webviewView.frame.width, height: windowHeight) + } + } +} + +extension ViewController: WKUIDelegate, WKDownloadDelegate { + // redirect new tabs to main webview + func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + if (navigationAction.targetFrame == nil) { + webView.load(navigationAction.request) + } + return nil + } + // restrict navigation to target host, open external links in 3rd party apps + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if (navigationAction.request.url?.scheme == "about") { + return decisionHandler(.allow) + } + if (navigationAction.shouldPerformDownload || navigationAction.request.url?.scheme == "blob") { + return decisionHandler(.download) + } + + if let requestUrl = navigationAction.request.url{ + if let requestHost = requestUrl.host { + // NOTE: Match auth origin first, because host origin may be a subset of auth origin and may therefore always match + let matchingAuthOrigin = authOrigins.first(where: { requestHost.range(of: $0) != nil }) + if (matchingAuthOrigin != nil) { + decisionHandler(.allow) + if (toolbarView.isHidden) { + toolbarView.isHidden = false + webView.frame = calcWebviewFrame(webviewView: webviewView, toolbarView: toolbarView) + } + return + } + + let matchingHostOrigin = allowedOrigins.first(where: { requestHost.range(of: $0) != nil }) + if (matchingHostOrigin != nil) { + // Open in main webview + decisionHandler(.allow) + if (!toolbarView.isHidden) { + toolbarView.isHidden = true + webView.frame = calcWebviewFrame(webviewView: webviewView, toolbarView: nil) + } + return + } + if (navigationAction.navigationType == .other && + navigationAction.value(forKey: "syntheticClickType") as! Int == 0 && + (navigationAction.targetFrame != nil) && + // no error here, fake warning + (navigationAction.sourceFrame != nil) + ) { + decisionHandler(.allow) + return + } + else { + decisionHandler(.cancel) + } + + + if ["http", "https"].contains(requestUrl.scheme?.lowercased() ?? "") { + // Can open with SFSafariViewController + let safariViewController = SFSafariViewController(url: requestUrl) + self.present(safariViewController, animated: true, completion: nil) + } else { + // Scheme is not supported or no scheme is given, use openURL + if (UIApplication.shared.canOpenURL(requestUrl)) { + UIApplication.shared.open(requestUrl) + } + } + } else { + decisionHandler(.cancel) + if (navigationAction.request.url?.scheme == "tel" || navigationAction.request.url?.scheme == "mailto" ){ + if (UIApplication.shared.canOpenURL(requestUrl)) { + UIApplication.shared.open(requestUrl) + } + } + else { + if requestUrl.isFileURL { + // not tested + downloadAndOpenFile(url: requestUrl.absoluteURL) + } + // if (requestUrl.absoluteString.contains("base64")){ + // downloadAndOpenBase64File(base64String: requestUrl.absoluteString) + // } + } + } + } + else { + decisionHandler(.cancel) + } + + } + // Handle javascript: `window.alert(message: String)` + func webView(_ webView: WKWebView, + runJavaScriptAlertPanelWithMessage message: String, + initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping () -> Void) { + + // Set the message as the UIAlertController message + let alert = UIAlertController( + title: nil, + message: message, + preferredStyle: .alert + ) + + // Add a confirmation action “OK” + let okAction = UIAlertAction( + title: "OK", + style: .default, + handler: { _ in + // Call completionHandler + completionHandler() + } + ) + alert.addAction(okAction) + + // Display the NSAlert + present(alert, animated: true, completion: nil) + } + // Handle javascript: `window.confirm(message: String)` + func webView(_ webView: WKWebView, + runJavaScriptConfirmPanelWithMessage message: String, + initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping (Bool) -> Void) { + + // Set the message as the UIAlertController message + let alert = UIAlertController( + title: nil, + message: message, + preferredStyle: .alert + ) + + // Add a confirmation action “Cancel” + let cancelAction = UIAlertAction( + title: "Cancel", + style: .cancel, + handler: { _ in + // Call completionHandler + completionHandler(false) + } + ) + + // Add a confirmation action “OK” + let okAction = UIAlertAction( + title: "OK", + style: .default, + handler: { _ in + // Call completionHandler + completionHandler(true) + } + ) + alert.addAction(cancelAction) + alert.addAction(okAction) + + // Display the NSAlert + present(alert, animated: true, completion: nil) + } + // Handle javascript: `window.prompt(prompt: String, defaultText: String?)` + func webView(_ webView: WKWebView, + runJavaScriptTextInputPanelWithPrompt prompt: String, + defaultText: String?, + initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping (String?) -> Void) { + + // Set the message as the UIAlertController message + let alert = UIAlertController( + title: nil, + message: prompt, + preferredStyle: .alert + ) + + // Add a confirmation action “Cancel” + let cancelAction = UIAlertAction( + title: "Cancel", + style: .cancel, + handler: { _ in + // Call completionHandler + completionHandler(nil) + } + ) + + // Add a confirmation action “OK” + let okAction = UIAlertAction( + title: "OK", + style: .default, + handler: { _ in + // Call completionHandler with Alert input + if let input = alert.textFields?.first?.text { + completionHandler(input) + } + } + ) + + alert.addTextField { textField in + textField.placeholder = defaultText + } + alert.addAction(cancelAction) + alert.addAction(okAction) + + // Display the NSAlert + present(alert, animated: true, completion: nil) + } + + func downloadAndOpenFile(url: URL){ + + let destinationFileUrl = url + let sessionConfig = URLSessionConfiguration.default + let session = URLSession(configuration: sessionConfig) + let request = URLRequest(url:url) + let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in + if let tempLocalUrl = tempLocalUrl, error == nil { + if let statusCode = (response as? HTTPURLResponse)?.statusCode { + print("Successfully download. Status code: \(statusCode)") + } + do { + try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl) + self.openFile(url: destinationFileUrl) + } catch (let writeError) { + print("Error creating a file \(destinationFileUrl) : \(writeError)") + } + } else { + print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "N/A") ") + } + } + task.resume() + } + + // func downloadAndOpenBase64File(base64String: String) { + // // Split the base64 string to extract the data and the file extension + // let components = base64String.components(separatedBy: ";base64,") + + // // Make sure the base64 string has the correct format + // guard components.count == 2, let format = components.first?.split(separator: "/").last else { + // print("Invalid base64 string format") + // return + // } + + // // Remove the data type prefix to get the base64 data + // let dataString = components.last! + + // if let imageData = Data(base64Encoded: dataString) { + // let documentsUrl: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + // let destinationFileUrl = documentsUrl.appendingPathComponent("image.\(format)") + + // do { + // try imageData.write(to: destinationFileUrl) + // self.openFile(url: destinationFileUrl) + // } catch { + // print("Error writing image to file url: \(destinationFileUrl): \(error)") + // } + // } + // } + + func openFile(url: URL) { + self.documentController = UIDocumentInteractionController(url: url) + self.documentController?.delegate = self + self.documentController?.presentPreview(animated: true) + } + + func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) { + download.delegate = self + } + + func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, + suggestedFilename: String, + completionHandler: @escaping (URL?) -> Void) { + + let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + let fileURL = documentsPath.appendingPathComponent(suggestedFilename) + + self.openFile(url: fileURL) + completionHandler(fileURL) + } +} diff --git a/src/Podfile b/src/Podfile new file mode 100644 index 0000000..50c38c8 --- /dev/null +++ b/src/Podfile @@ -0,0 +1,21 @@ +# Uncomment the next line to define a global platform for your project +platform :ios, '15.0' + +target 'Nivesh' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Add the pod for Firebase Cloud Messaging + pod 'FirebaseCore' + pod 'FirebaseAnalytics' + pod 'Firebase/Messaging' + +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' + end + end +end diff --git a/src/launch-128.png b/src/launch-128.png new file mode 100644 index 0000000..6e22358 Binary files /dev/null and b/src/launch-128.png differ diff --git a/src/launch-192.png b/src/launch-192.png new file mode 100644 index 0000000..7f773d7 Binary files /dev/null and b/src/launch-192.png differ diff --git a/src/launch-256.png b/src/launch-256.png new file mode 100644 index 0000000..d556a0f Binary files /dev/null and b/src/launch-256.png differ diff --git a/src/launch-512.png b/src/launch-512.png new file mode 100644 index 0000000..01cc14b Binary files /dev/null and b/src/launch-512.png differ diff --git a/src/launch-64.png b/src/launch-64.png new file mode 100644 index 0000000..56567ca Binary files /dev/null and b/src/launch-64.png differ