commit 4cc1b4cca5659c76c80edb5e10b035b2f9fcecf0 Author: pscb-dev <> Date: Mon Jul 8 15:20:00 2024 +0300 init diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..139d470 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1 @@ +LICENSE BE HERE diff --git a/PSCBOnline.podspec b/PSCBOnline.podspec new file mode 100644 index 0000000..ea1b41b --- /dev/null +++ b/PSCBOnline.podspec @@ -0,0 +1,138 @@ +# +# Be sure to run `pod spec lint PSCBOnline.podspec' to ensure this is a +# valid spec and to remove all comments including this before submitting the spec. +# +# To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html +# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ +# + +Pod::Spec.new do |spec| + + # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # These will help people to find your library, and whilst it + # can feel like a chore to fill in it's definitely to your advantage. The + # summary should be tweet-length, and the description more in depth. + # + + spec.name = "PSCBOnline" + spec.version = "1.0.1" + spec.summary = "An iOS SDK for PSCB Online (OOS) acquiring protocol." + + # This description is used to generate tags and improve search results. + # * Think: What does it do? Why did you write it? What is the focus? + # * Try to keep it short, snappy and to the point. + # * Write the description between the DESC delimiters below. + # * Finally, don't worry about the indent, CocoaPods strips it! + spec.description = "An implementation of PSCB-Online (oos.pscb.ru) acquiring protocol for iOS platforms." + + spec.homepage = "https://oos.pscb.ru/" + # spec.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" + + + # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # Licensing your code is important. See https://choosealicense.com for more info. + # CocoaPods will detect a license file if there is a named LICENSE* + # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. + # + + spec.license = { :type => "PSCB", :file => "LICENSE.txt" } + # spec.license = { :type => "MIT", :file => "FILE_LICENSE" } + + + # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # Specify the authors of the library, with email addresses. Email addresses + # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also + # accepts just a name if you'd rather not provide an email address. + # + # Specify a social_media_url where others can refer to, for example a twitter + # profile URL. + # + + spec.authors = { "Antonov Ilia" => "antilya@gmail.com" } + + # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # If this Pod runs only on iOS or OS X, then specify the platform and + # the deployment target. You can optionally include the target after the platform. + # + + # spec.platform = :ios + spec.platform = :ios, "10.0" + + # When using multiple platforms + spec.ios.deployment_target = "10.0" + # spec.osx.deployment_target = "10.7" + # spec.watchos.deployment_target = "2.0" + # spec.tvos.deployment_target = "9.0" + + + # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # Specify the location from where the source should be retrieved. + # Supports git, hg, bzr, svn and HTTP. + # + + #spec.source = { :git => "http://EXAMPLE/PSCB_OOS.git", :tag => "#{spec.version}" } + spec.source = { :git => "https://bitbucket.org/dev_ai/oos-ios.git", :tag => "#{spec.version}" } + + + # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # CocoaPods is smart about how it includes source code. For source files + # giving a folder will include any swift, h, m, mm, c & cpp files. + # For header files it will include any header in the folder. + # Not including the public_header_files will make all headers public. + # + + #spec.source_files = "PSCBOnline", "PSCBOnline/**/*.{h,m,swift}", "PSCBOnline/Sources/**/*.{h,m,swift}" + spec.source_files = "PSCBOnline/**/*.{h,m,swift}" + # spec.source_files = "PSCB-OOS-iOS", "PSCB-OOS-iOS/**/*.{h,m}" + spec.exclude_files = "" + + # spec.public_header_files = "Classes/**/*.h" + + + # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # A list of resources included with the Pod. These are copied into the + # target bundle with a build phase script. Anything else will be cleaned. + # You can preserve files from being cleaned, please don't preserve + # non-essential files like tests, examples and documentation. + # + + # spec.resource = "icon.png" + # spec.resources = "Resources/*.png" + + # spec.preserve_paths = "FilesToSave", "MoreFilesToSave" + + + # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # Link your library with frameworks, or libraries. Libraries do not include + # the lib prefix of their name. + # + + # spec.framework = "SomeFramework" + # spec.frameworks = "SomeFramework", "AnotherFramework" + + # spec.library = "iconv" + # spec.libraries = "iconv", "xml2" + + + # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # + # + # If your library depends on compiler flags you can set them in the xcconfig hash + # where they will only apply to your library. If you depend on other Podspecs + # you can include multiple dependencies to ensure it works. + + # spec.requires_arc = true + + # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } + # spec.dependency "JSONKit", "~> 1.4" + + spec.swift_version = "5.3" + +end diff --git a/PSCBOnline.xcodeproj/project.pbxproj b/PSCBOnline.xcodeproj/project.pbxproj new file mode 100644 index 0000000..84f6dfb --- /dev/null +++ b/PSCBOnline.xcodeproj/project.pbxproj @@ -0,0 +1,652 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0E01EAB425399CB500B0759B /* PSCBOnline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E01EAAA25399CB500B0759B /* PSCBOnline.framework */; }; + 0E01EAB925399CB500B0759B /* PSCBOnlineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EAB825399CB500B0759B /* PSCBOnlineTests.swift */; }; + 0E01EABB25399CB500B0759B /* PSCBOnline.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E01EAAD25399CB500B0759B /* PSCBOnline.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E01EACD25399DB000B0759B /* Payment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EACC25399DB000B0759B /* Payment.swift */; }; + 0E01EAD325399DF600B0759B /* CustomerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EAD225399DF500B0759B /* CustomerData.swift */; }; + 0E01EAD825399E3D00B0759B /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EAD725399E3D00B0759B /* String.swift */; }; + 0E01EADE25399E8800B0759B /* RequestWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EADD25399E8800B0759B /* RequestWrapper.swift */; }; + 0E01EAE425399EE800B0759B /* PaymentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E01EAE325399EE800B0759B /* PaymentTests.swift */; }; + 0E0A2C1F25408AA1006BBBA1 /* CardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A2C1E25408AA1006BBBA1 /* CardData.swift */; }; + 0E0A2C23254093D0006BBBA1 /* Payment+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A2C22254093D0006BBBA1 /* Payment+Serializable.swift */; }; + 0E26F5862542FB5800F80DAC /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F5852542FB5800F80DAC /* Response.swift */; }; + 0E26F58A2542FE2000F80DAC /* ResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F5892542FE2000F80DAC /* ResponseTests.swift */; }; + 0E26F58F2545AE5800F80DAC /* JSONDecoders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F58E2545AE5800F80DAC /* JSONDecoders.swift */; }; + 0E26F59F2547097300F80DAC /* RSAHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F59E2547097300F80DAC /* RSAHelper.swift */; }; + 0E26F5A3254714B600F80DAC /* CardDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F5A2254714B600F80DAC /* CardDataTests.swift */; }; + 0E26F5E82548717B00F80DAC /* PSCBAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F5E72548717B00F80DAC /* PSCBAPI.swift */; }; + 0E26F62E2549591E00F80DAC /* DigestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F62D2549591D00F80DAC /* DigestHelper.swift */; }; + 0E26F63325495A5B00F80DAC /* DigestHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26F63225495A5B00F80DAC /* DigestHelperTests.swift */; }; + 0E790FA3253DEA930086AD71 /* PSCBOnline.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 0E790FA2253DEA930086AD71 /* PSCBOnline.podspec */; }; + 0E790FAB253E017E0086AD71 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 0E790FAA253E017E0086AD71 /* LICENSE.txt */; }; + 0EA2C84E2539A5BA00C5DD14 /* Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2C84D2539A5BA00C5DD14 /* Serializable.swift */; }; + 0EA2C8582539F4D500C5DD14 /* PSCBOnlineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2C8572539F4D500C5DD14 /* PSCBOnlineClient.swift */; }; + 0EA2C8622539FAC200C5DD14 /* PaymentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2C8612539FAC200C5DD14 /* PaymentHandler.swift */; }; + 0EA2C86A253B29A900C5DD14 /* PKPaymentToken+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2C869253B29A900C5DD14 /* PKPaymentToken+Serializable.swift */; }; + 0EA2C872253CC44A00C5DD14 /* RequestWrapper+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2C871253CC44A00C5DD14 /* RequestWrapper+Serializable.swift */; }; + 0EC9DB072540A1C8005392A0 /* OOSAPIClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC9DB062540A1C8005392A0 /* OOSAPIClientTests.swift */; }; + 0EC9DB0C2541B699005392A0 /* PassKitMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC9DB0B2541B699005392A0 /* PassKitMocks.swift */; }; + 0EC9DB132541BF45005392A0 /* PKPaymentToken+SerializableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC9DB122541BF45005392A0 /* PKPaymentToken+SerializableTests.swift */; }; + 0EC9DB192541D9F9005392A0 /* PKPaymentTokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC9DB182541D9F9005392A0 /* PKPaymentTokenTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0E01EAB525399CB500B0759B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0E01EAA125399CB500B0759B /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0E01EAA925399CB500B0759B; + remoteInfo = "PSCB-OOS-iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0E01EAAA25399CB500B0759B /* PSCBOnline.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PSCBOnline.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0E01EAAD25399CB500B0759B /* PSCBOnline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PSCBOnline.h; sourceTree = ""; }; + 0E01EAAE25399CB500B0759B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0E01EAB325399CB500B0759B /* PSCBOnlineTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PSCBOnlineTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0E01EAB825399CB500B0759B /* PSCBOnlineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSCBOnlineTests.swift; sourceTree = ""; }; + 0E01EABA25399CB500B0759B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0E01EACC25399DB000B0759B /* Payment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Payment.swift; sourceTree = ""; }; + 0E01EAD225399DF500B0759B /* CustomerData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerData.swift; sourceTree = ""; }; + 0E01EAD725399E3D00B0759B /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; + 0E01EADD25399E8800B0759B /* RequestWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestWrapper.swift; sourceTree = ""; }; + 0E01EAE325399EE800B0759B /* PaymentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTests.swift; sourceTree = ""; }; + 0E0A2C1E25408AA1006BBBA1 /* CardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardData.swift; sourceTree = ""; }; + 0E0A2C22254093D0006BBBA1 /* Payment+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Payment+Serializable.swift"; sourceTree = ""; }; + 0E26F5852542FB5800F80DAC /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = ""; }; + 0E26F5892542FE2000F80DAC /* ResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseTests.swift; sourceTree = ""; }; + 0E26F58E2545AE5800F80DAC /* JSONDecoders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONDecoders.swift; sourceTree = ""; }; + 0E26F59E2547097300F80DAC /* RSAHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSAHelper.swift; sourceTree = ""; }; + 0E26F5A2254714B600F80DAC /* CardDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardDataTests.swift; sourceTree = ""; }; + 0E26F5E72548717B00F80DAC /* PSCBAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSCBAPI.swift; sourceTree = ""; }; + 0E26F62D2549591D00F80DAC /* DigestHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigestHelper.swift; sourceTree = ""; }; + 0E26F63225495A5B00F80DAC /* DigestHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigestHelperTests.swift; sourceTree = ""; }; + 0E547EB32552BEA500E0F8C0 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 0E790FA2253DEA930086AD71 /* PSCBOnline.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PSCBOnline.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 0E790FAA253E017E0086AD71 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; + 0EA2C84D2539A5BA00C5DD14 /* Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Serializable.swift; sourceTree = ""; }; + 0EA2C8572539F4D500C5DD14 /* PSCBOnlineClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSCBOnlineClient.swift; sourceTree = ""; }; + 0EA2C8612539FAC200C5DD14 /* PaymentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentHandler.swift; sourceTree = ""; }; + 0EA2C869253B29A900C5DD14 /* PKPaymentToken+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PKPaymentToken+Serializable.swift"; sourceTree = ""; }; + 0EA2C871253CC44A00C5DD14 /* RequestWrapper+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RequestWrapper+Serializable.swift"; sourceTree = ""; }; + 0EC9DB062540A1C8005392A0 /* OOSAPIClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOSAPIClientTests.swift; sourceTree = ""; }; + 0EC9DB0B2541B699005392A0 /* PassKitMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassKitMocks.swift; sourceTree = ""; }; + 0EC9DB122541BF45005392A0 /* PKPaymentToken+SerializableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PKPaymentToken+SerializableTests.swift"; sourceTree = ""; }; + 0EC9DB182541D9F9005392A0 /* PKPaymentTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKPaymentTokenTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0E01EAA725399CB500B0759B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E01EAB025399CB500B0759B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E01EAB425399CB500B0759B /* PSCBOnline.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0E01EAA025399CB500B0759B = { + isa = PBXGroup; + children = ( + 0E547EB32552BEA500E0F8C0 /* README.md */, + 0E790FAA253E017E0086AD71 /* LICENSE.txt */, + 0E790FA2253DEA930086AD71 /* PSCBOnline.podspec */, + 0E01EAAC25399CB500B0759B /* PSCBOnline */, + 0E01EAB725399CB500B0759B /* PSCBOnlineTests */, + 0E01EAAB25399CB500B0759B /* Products */, + ); + sourceTree = ""; + }; + 0E01EAAB25399CB500B0759B /* Products */ = { + isa = PBXGroup; + children = ( + 0E01EAAA25399CB500B0759B /* PSCBOnline.framework */, + 0E01EAB325399CB500B0759B /* PSCBOnlineTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0E01EAAC25399CB500B0759B /* PSCBOnline */ = { + isa = PBXGroup; + children = ( + 0E01EAC625399CEF00B0759B /* Sources */, + 0E01EAAD25399CB500B0759B /* PSCBOnline.h */, + 0E01EAAE25399CB500B0759B /* Info.plist */, + ); + path = PSCBOnline; + sourceTree = ""; + }; + 0E01EAB725399CB500B0759B /* PSCBOnlineTests */ = { + isa = PBXGroup; + children = ( + 0E26F63125495A2F00F80DAC /* Helpers */, + 0EC9DB112541BF2D005392A0 /* Serializable */, + 0EC9DB0A2541B686005392A0 /* Mocks */, + 0E01EAE125399ECE00B0759B /* Sources */, + 0E01EAB825399CB500B0759B /* PSCBOnlineTests.swift */, + 0E01EABA25399CB500B0759B /* Info.plist */, + ); + path = PSCBOnlineTests; + sourceTree = ""; + }; + 0E01EAC625399CEF00B0759B /* Sources */ = { + isa = PBXGroup; + children = ( + 0E26F58D2545AE4200F80DAC /* Helpers */, + 0EA2C84C2539A5A300C5DD14 /* Serializable */, + 0E01EAD625399E0F00B0759B /* Extension */, + 0E01EACB25399D8F00B0759B /* Models */, + 0EA2C8572539F4D500C5DD14 /* PSCBOnlineClient.swift */, + 0EA2C8612539FAC200C5DD14 /* PaymentHandler.swift */, + 0E26F5E72548717B00F80DAC /* PSCBAPI.swift */, + ); + path = Sources; + sourceTree = ""; + }; + 0E01EACB25399D8F00B0759B /* Models */ = { + isa = PBXGroup; + children = ( + 0E01EACC25399DB000B0759B /* Payment.swift */, + 0E01EAD225399DF500B0759B /* CustomerData.swift */, + 0E01EADD25399E8800B0759B /* RequestWrapper.swift */, + 0E0A2C1E25408AA1006BBBA1 /* CardData.swift */, + 0E26F5852542FB5800F80DAC /* Response.swift */, + ); + path = Models; + sourceTree = ""; + }; + 0E01EAD625399E0F00B0759B /* Extension */ = { + isa = PBXGroup; + children = ( + 0E01EAD725399E3D00B0759B /* String.swift */, + ); + path = Extension; + sourceTree = ""; + }; + 0E01EAE125399ECE00B0759B /* Sources */ = { + isa = PBXGroup; + children = ( + 0E01EAE225399ED400B0759B /* Models */, + 0EC9DB062540A1C8005392A0 /* OOSAPIClientTests.swift */, + ); + path = Sources; + sourceTree = ""; + }; + 0E01EAE225399ED400B0759B /* Models */ = { + isa = PBXGroup; + children = ( + 0E01EAE325399EE800B0759B /* PaymentTests.swift */, + 0E26F5892542FE2000F80DAC /* ResponseTests.swift */, + 0E26F5A2254714B600F80DAC /* CardDataTests.swift */, + ); + path = Models; + sourceTree = ""; + }; + 0E26F58D2545AE4200F80DAC /* Helpers */ = { + isa = PBXGroup; + children = ( + 0E26F58E2545AE5800F80DAC /* JSONDecoders.swift */, + 0E26F59E2547097300F80DAC /* RSAHelper.swift */, + 0E26F62D2549591D00F80DAC /* DigestHelper.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 0E26F63125495A2F00F80DAC /* Helpers */ = { + isa = PBXGroup; + children = ( + 0E26F63225495A5B00F80DAC /* DigestHelperTests.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 0EA2C84C2539A5A300C5DD14 /* Serializable */ = { + isa = PBXGroup; + children = ( + 0EA2C84D2539A5BA00C5DD14 /* Serializable.swift */, + 0EA2C869253B29A900C5DD14 /* PKPaymentToken+Serializable.swift */, + 0EA2C871253CC44A00C5DD14 /* RequestWrapper+Serializable.swift */, + 0E0A2C22254093D0006BBBA1 /* Payment+Serializable.swift */, + ); + path = Serializable; + sourceTree = ""; + }; + 0EC9DB0A2541B686005392A0 /* Mocks */ = { + isa = PBXGroup; + children = ( + 0EC9DB0B2541B699005392A0 /* PassKitMocks.swift */, + ); + path = Mocks; + sourceTree = ""; + }; + 0EC9DB112541BF2D005392A0 /* Serializable */ = { + isa = PBXGroup; + children = ( + 0EC9DB122541BF45005392A0 /* PKPaymentToken+SerializableTests.swift */, + 0EC9DB182541D9F9005392A0 /* PKPaymentTokenTests.swift */, + ); + path = Serializable; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0E01EAA525399CB500B0759B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E01EABB25399CB500B0759B /* PSCBOnline.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 0E01EAA925399CB500B0759B /* PSCBOnline */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E01EABE25399CB500B0759B /* Build configuration list for PBXNativeTarget "PSCBOnline" */; + buildPhases = ( + 0E01EAA525399CB500B0759B /* Headers */, + 0E01EAA625399CB500B0759B /* Sources */, + 0E01EAA725399CB500B0759B /* Frameworks */, + 0E01EAA825399CB500B0759B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PSCBOnline; + productName = "PSCB-OOS-iOS"; + productReference = 0E01EAAA25399CB500B0759B /* PSCBOnline.framework */; + productType = "com.apple.product-type.framework"; + }; + 0E01EAB225399CB500B0759B /* PSCBOnlineTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E01EAC125399CB500B0759B /* Build configuration list for PBXNativeTarget "PSCBOnlineTests" */; + buildPhases = ( + 0E01EAAF25399CB500B0759B /* Sources */, + 0E01EAB025399CB500B0759B /* Frameworks */, + 0E01EAB125399CB500B0759B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0E01EAB625399CB500B0759B /* PBXTargetDependency */, + ); + name = PSCBOnlineTests; + productName = "PSCB-OOS-iOSTests"; + productReference = 0E01EAB325399CB500B0759B /* PSCBOnlineTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0E01EAA125399CB500B0759B /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1200; + LastUpgradeCheck = 1200; + TargetAttributes = { + 0E01EAA925399CB500B0759B = { + CreatedOnToolsVersion = 12.0.1; + LastSwiftMigration = 1200; + }; + 0E01EAB225399CB500B0759B = { + CreatedOnToolsVersion = 12.0.1; + }; + }; + }; + buildConfigurationList = 0E01EAA425399CB500B0759B /* Build configuration list for PBXProject "PSCBOnline" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0E01EAA025399CB500B0759B; + productRefGroup = 0E01EAAB25399CB500B0759B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0E01EAA925399CB500B0759B /* PSCBOnline */, + 0E01EAB225399CB500B0759B /* PSCBOnlineTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0E01EAA825399CB500B0759B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E790FAB253E017E0086AD71 /* LICENSE.txt in Resources */, + 0E790FA3253DEA930086AD71 /* PSCBOnline.podspec in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E01EAB125399CB500B0759B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0E01EAA625399CB500B0759B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E26F59F2547097300F80DAC /* RSAHelper.swift in Sources */, + 0EA2C872253CC44A00C5DD14 /* RequestWrapper+Serializable.swift in Sources */, + 0EA2C86A253B29A900C5DD14 /* PKPaymentToken+Serializable.swift in Sources */, + 0E0A2C1F25408AA1006BBBA1 /* CardData.swift in Sources */, + 0EA2C84E2539A5BA00C5DD14 /* Serializable.swift in Sources */, + 0E0A2C23254093D0006BBBA1 /* Payment+Serializable.swift in Sources */, + 0E26F5E82548717B00F80DAC /* PSCBAPI.swift in Sources */, + 0E26F5862542FB5800F80DAC /* Response.swift in Sources */, + 0E26F58F2545AE5800F80DAC /* JSONDecoders.swift in Sources */, + 0E01EAD325399DF600B0759B /* CustomerData.swift in Sources */, + 0E01EACD25399DB000B0759B /* Payment.swift in Sources */, + 0EA2C8582539F4D500C5DD14 /* PSCBOnlineClient.swift in Sources */, + 0EA2C8622539FAC200C5DD14 /* PaymentHandler.swift in Sources */, + 0E01EADE25399E8800B0759B /* RequestWrapper.swift in Sources */, + 0E26F62E2549591E00F80DAC /* DigestHelper.swift in Sources */, + 0E01EAD825399E3D00B0759B /* String.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E01EAAF25399CB500B0759B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0EC9DB072540A1C8005392A0 /* OOSAPIClientTests.swift in Sources */, + 0EC9DB192541D9F9005392A0 /* PKPaymentTokenTests.swift in Sources */, + 0EC9DB0C2541B699005392A0 /* PassKitMocks.swift in Sources */, + 0E26F58A2542FE2000F80DAC /* ResponseTests.swift in Sources */, + 0EC9DB132541BF45005392A0 /* PKPaymentToken+SerializableTests.swift in Sources */, + 0E26F5A3254714B600F80DAC /* CardDataTests.swift in Sources */, + 0E26F63325495A5B00F80DAC /* DigestHelperTests.swift in Sources */, + 0E01EAE425399EE800B0759B /* PaymentTests.swift in Sources */, + 0E01EAB925399CB500B0759B /* PSCBOnlineTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0E01EAB625399CB500B0759B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0E01EAA925399CB500B0759B /* PSCBOnline */; + targetProxy = 0E01EAB525399CB500B0759B /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0E01EABC25399CB500B0759B /* 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; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.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"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 0E01EABD25399CB500B0759B /* 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; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 0E01EABF25399CB500B0759B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 46N426YCGP; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = PSCBOnline/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.oos-ios-sdk"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0E01EAC025399CB500B0759B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 46N426YCGP; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = PSCBOnline/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.oos-ios-sdk"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 0E01EAC225399CB500B0759B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = ru.pscb.PSCBOnlineTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0E01EAC325399CB500B0759B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = ru.pscb.PSCBOnlineTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0E01EAA425399CB500B0759B /* Build configuration list for PBXProject "PSCBOnline" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E01EABC25399CB500B0759B /* Debug */, + 0E01EABD25399CB500B0759B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0E01EABE25399CB500B0759B /* Build configuration list for PBXNativeTarget "PSCBOnline" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E01EABF25399CB500B0759B /* Debug */, + 0E01EAC025399CB500B0759B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0E01EAC125399CB500B0759B /* Build configuration list for PBXNativeTarget "PSCBOnlineTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E01EAC225399CB500B0759B /* Debug */, + 0E01EAC325399CB500B0759B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0E01EAA125399CB500B0759B /* Project object */; +} diff --git a/PSCBOnline.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PSCBOnline.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/PSCBOnline.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/PSCBOnline.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PSCBOnline.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PSCBOnline.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PSCBOnline.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate b/PSCBOnline.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..c937c36 Binary files /dev/null and b/PSCBOnline.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/PSCBOnline.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist b/PSCBOnline.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..0bcb71f --- /dev/null +++ b/PSCBOnline.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + PSCBOnline.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 0E01EAA925399CB500B0759B + + primary + + + 0E01EAB225399CB500B0759B + + primary + + + + + diff --git a/PSCBOnline/Info.plist b/PSCBOnline/Info.plist new file mode 100644 index 0000000..9bcb244 --- /dev/null +++ b/PSCBOnline/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/PSCBOnline/PSCBOnline.h b/PSCBOnline/PSCBOnline.h new file mode 100644 index 0000000..58e4a8b --- /dev/null +++ b/PSCBOnline/PSCBOnline.h @@ -0,0 +1,18 @@ +// +// PSCBOnline.h +// PSCBOnline +// +// Created by Antonov Ilia on 16.10.2020. +// + +#import + +//! Project version number for PSCBOnline. +FOUNDATION_EXPORT double PSCBOnlineVersionNumber; + +//! Project version string for PSCBOnline. +FOUNDATION_EXPORT const unsigned char PSCBOnlineVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/PSCBOnline/Sources/Extension/String.swift b/PSCBOnline/Sources/Extension/String.swift new file mode 100644 index 0000000..b9ff5b9 --- /dev/null +++ b/PSCBOnline/Sources/Extension/String.swift @@ -0,0 +1,26 @@ +// +// String.swift +// +// +// Created by AntonovIA on 12.10.2020. +// + +import Foundation + +extension String { + + private static let alphanumeric = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + static func random(length: Int, allowedChars: String? = nil) -> String { + let seq: String = ((allowedChars == nil) ? alphanumeric : allowedChars!) as String + var rnd: String = "" + + for _ in 0.. String { + let data = string.data(using: .utf8)! + var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + var sign = "" + + data.withUnsafeBytes { + _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash) + } + + for byte in hash { + sign += String(format: "%02x", UInt8(byte)) + } + + return sign.lowercased() + } + +} diff --git a/PSCBOnline/Sources/Helpers/JSONDecoders.swift b/PSCBOnline/Sources/Helpers/JSONDecoders.swift new file mode 100644 index 0000000..eb537e2 --- /dev/null +++ b/PSCBOnline/Sources/Helpers/JSONDecoders.swift @@ -0,0 +1,33 @@ +// +// JSONDecoders.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 25.10.2020. +// + +import Foundation + +final public class JSONDecoders { + + public static func iso8601DateAwareDecoder() -> JSONDecoder { + return ISO8601DateAwareJSONDecoder() + } + +} + +// MARK: - ISO8601 date aware JSON Decoder +class ISO8601DateAwareJSONDecoder: JSONDecoder { + + static internal let dateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" + + let dateFormatter: DateFormatter = DateFormatter() + let calendar = Calendar.current + + override init() { + super.init() + + dateFormatter.dateFormat = Self.dateTimeFormat + dateDecodingStrategy = .formatted(dateFormatter) + } + +} diff --git a/PSCBOnline/Sources/Helpers/RSAHelper.swift b/PSCBOnline/Sources/Helpers/RSAHelper.swift new file mode 100644 index 0000000..9b806f3 --- /dev/null +++ b/PSCBOnline/Sources/Helpers/RSAHelper.swift @@ -0,0 +1,86 @@ +// +// RSAHelper.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 26.10.2020. +// + +import Foundation + +enum RSAKeyError: Error { + + /// Thrown when provided public key is invalid + case invalidKey + + /// Thrown when encryption of message failed + case encryption(OSStatus) + + /// Thrown when unable to initialize `SecKey` with given key string + case unmanaged(Unmanaged) +} + +public final class RSAHelper { + + internal static let key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPQsWyHaynwoc2tuMbengf1SFase9tPnwtPh4o1tR+94xsWztADdhhUaUBk/68ipaoZE8uSnM9UgdEPmOotFXyUCAwEAAQ==" + + internal static var secKey: SecKey? = nil + + static func initPSCBOnlinePublicKey() throws { + // Treat as assert + guard let keyData = Data(base64Encoded: key) else { + print("Invalid key string: \(key)") + throw RSAKeyError.invalidKey + } + + var attributes: CFDictionary { + return [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeyClass: kSecAttrKeyClassPublic, + kSecAttrKeySizeInBits: 2048, + kSecReturnPersistentRef: true + ] as CFDictionary + } + + var error: Unmanaged? = nil + guard let secKey = SecKeyCreateWithData(keyData as CFData, attributes, &error) else { + print("Error creating a security key with \(String(describing: keyData))") + print(error.debugDescription) + throw RSAKeyError.unmanaged(error!) + } + + Self.secKey = secKey + } + + /// Encrypts given message with OOS public key. + /// + /// - Parameters: + /// - message: A message to encrypt. + /// + /// - Returns: A base64 encoded string + /// + /// - Throws: `RSAKeyError` type error + public static func encryptEncodeBase64(message: String) throws -> String { + // Initialize OOS public key + if Self.secKey == nil { + try Self.initPSCBOnlinePublicKey() + } + + // Initialize buffers + let sKey = Self.secKey! + let buff = [UInt8](message.utf8) + + // Mutable encryption refs + var size = SecKeyGetBlockSize(sKey) + var kBuf = [UInt8](repeating: 0, count: size) + + let status = SecKeyEncrypt(sKey, SecPadding.PKCS1, buff, buff.count, &kBuf, &size) + + // Sanity check + guard status == errSecSuccess else { + throw RSAKeyError.encryption(status) + } + + return Data(bytes: kBuf, count: size).base64EncodedString() + } + +} diff --git a/PSCBOnline/Sources/Models/CardData.swift b/PSCBOnline/Sources/Models/CardData.swift new file mode 100644 index 0000000..bd8ed9a --- /dev/null +++ b/PSCBOnline/Sources/Models/CardData.swift @@ -0,0 +1,92 @@ +// +// CardData.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 21.10.2020. +// + +import Foundation +import PassKit + +public enum CardDataError: Error { + case invalidExiryDate(String) + case invalidCvCode + case invalidPan +} + +/// Billing info. +/// Detailed card information +public struct CardData { + let pan: String + let expiryYear: Int + let expiryMonth: Int + let cardholder: String? + let cvCode: String + + /// Constructs card data from all necessary for billing fields + /// + /// - Parameters: + /// - pan: Card number + /// - expiryYear: A full year number (e.g: `2020`). For production cannot be in the past + /// - expiryMonth: A month number from 1 to 12. + /// - cvCode: CVC/CVV number + /// - cardholder: (Optional) Cardholder name in latin. + /// + /// - Returns: optional instance of a new card. If validation fails returns nil + public init?(pan: String, expiryYear: Int, expiryMonth: Int, cvCode: String, cardholder: String? = nil) { + guard expiryMonth >= 1 && expiryMonth <= 12 else { + print("Month can be between 1 and 12") + return nil + } + + #if !DEBUG + // todo check year + month in the past + let currentYear = Calendar.current.component(.year, from: Date()) + guard expiryYear >= currentYear else { + print("Year must be current or in the future") + return nil + } + #endif + + self.pan = pan + self.expiryMonth = expiryMonth + self.expiryYear = expiryYear + self.cvCode = cvCode + self.cardholder = cardholder + } + + /// - Returns: A last 2 digits of the expiry year + public func getExpYearString() -> String { + return String(String(expiryYear).dropFirst(2)) + } + + /// - Returns: A zero padded expiry month string + public func getExpMonthString() -> String { + return expiryMonth < 10 ? "0\(self.expiryMonth)" : String(self.expiryMonth) + } + +} + +extension CardData { + + internal static let pubKey: Data = { + let key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPQsWyHaynwoc2tuMbengf1SFase9tPnwtPh4o1tR+94xsWztADdhhUaUBk/68ipaoZE8uSnM9UgdEPmOotFXyUCAwEAAQ==" + + return Data(base64Encoded: key)! + }() + + + /// Produces a cryptogram string from given `CardData` + /// See: https://docs.pscb.ru/oos/shpa.html#shlyuz-prozrachnoj-avtorizacii-sozdanie-platezha-otvet + /// + /// - Returns: a Base64 encoded cryptogram string + public func toCryptgramString() throws -> String { + let month = self.getExpMonthString() + let year = self.getExpYearString() + let joinedString = "\(self.pan)|\(month)|\(year)|\(cvCode)\(self.cardholder ?? "")" + let base64Encode = try RSAHelper.encryptEncodeBase64(message: joinedString) + + return base64Encode + } + +} diff --git a/PSCBOnline/Sources/Models/CustomerData.swift b/PSCBOnline/Sources/Models/CustomerData.swift new file mode 100644 index 0000000..710ea0b --- /dev/null +++ b/PSCBOnline/Sources/Models/CustomerData.swift @@ -0,0 +1,29 @@ +// +// CustomerData.swift +// +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation + +/// A costumer data to present in PaymentData +public struct CustomerData: Codable { + + /// Unique costumer ID + let account: String + + let comment: String? + + let email: String? + + let phone: String? + + enum CodingKeys: String, CodingKey { + case account = "customerAccount" + case comment = "customerComment" + case email = "customerEmail" + case phone = "customerPhone" + } + +} diff --git a/PSCBOnline/Sources/Models/Payment.swift b/PSCBOnline/Sources/Models/Payment.swift new file mode 100644 index 0000000..74b0b37 --- /dev/null +++ b/PSCBOnline/Sources/Models/Payment.swift @@ -0,0 +1,90 @@ +// +// Payment.swift +// +// +// Created by AntonovIA on 12.10.2020. +// + +import Foundation + +// MARK: - Payment methods + +internal enum PaymentMethods: String { + case shpa = "ac-shpa" +} + +// MARK: - Request Message + +public struct Payment: Encodable { + + // Required: + + /// Payment amount in rub + /// min: 1.00 + public let amount: Decimal + + /// Your market order ID + /// maxlength: 20 + public let orderId: String + + // Payment method + internal let paymentMethod: PaymentMethods = .shpa + + // Optional: + + /// Human readable `orderId` + /// Defaults to `orderId` + var showOrderId: String? + + /// Detailed text describing this order payment. + var details: String? + + /// Data about paying customer + var customer: CustomerData? + + // + var recurrentable: Bool = false + + public init(amount: Decimal, orderId: String, + showOrderId: String? = nil, details: String? = nil, + customer: CustomerData? = nil, recurrentable: Bool = false) { + self.amount = amount + self.orderId = orderId + self.showOrderId = (showOrderId == nil) ? orderId : showOrderId + self.details = details + self.customer = customer + self.recurrentable = recurrentable + } + + // MARK: - Encoder + + private enum CodingKeys: String, CodingKey { + case amount, orderId, showOrderId, details, recurrentable, customer + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(amount, forKey: .amount) + try container.encode(orderId, forKey: .orderId) + try container.encode(showOrderId, forKey: .showOrderId) + try container.encode(details, forKey: .details) + try container.encode(recurrentable, forKey: .recurrentable) + + // Customer + try customer?.encode(to: encoder) + } + + #if DEBUG + + public static let example = Payment( + amount: 150.00, orderId: String.random(length: 6), + details: "Wonderful warm socks", + customer: CustomerData( + account: "ID-12345", comment: "By tomorrow please", + email: "foo@bar.com", phone: "+7 900 000 00 00" + ) + ) + + #endif + +} diff --git a/PSCBOnline/Sources/Models/RequestWrapper.swift b/PSCBOnline/Sources/Models/RequestWrapper.swift new file mode 100644 index 0000000..ad4aebc --- /dev/null +++ b/PSCBOnline/Sources/Models/RequestWrapper.swift @@ -0,0 +1,44 @@ +// +// RequestWrapper.swift +// +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation + +// MARK: - Top level request + +/// Top level request wrapper for OOS requests +public struct RequestWrapper: Encodable { + + /// Merchant ID + public let marketPlaceId: String + + /// Payment info + public let payment: Payment + + /// Encoded card data + public let cardData: String + + /// Creates instance of RequestWrapper + /// + /// - Parameters: + /// - marketPlaceId: Your OOS market place ID + /// - payment: Payment details object + /// - cardData: Encoded card data + /// + /// - Returns: Prepared request ready to fire + public init(marketPlaceId: String, payment: Payment, cardData: String) { + self.marketPlaceId = marketPlaceId + self.payment = payment + self.cardData = cardData + } + + private enum CodingKeys: String, CodingKey { + case marketPlaceId = "marketPlace" + case payment + case cardData + } + +} diff --git a/PSCBOnline/Sources/Models/Response.swift b/PSCBOnline/Sources/Models/Response.swift new file mode 100644 index 0000000..d23f383 --- /dev/null +++ b/PSCBOnline/Sources/Models/Response.swift @@ -0,0 +1,100 @@ +// +// Response.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 23.10.2020. +// + +import Foundation + +// MARK: - PSCB OOS Response status +public enum ResponseStatus: String, Decodable { + case success = "STATUS_SUCCESS" + case failure = "STATUS_FAILURE" +} + +// MARK: - Acquiring data +public struct AcquiringResponseData: Decodable { + public let paReq: String? + public let order: String? + public let termUrl: String? + public let url: String? + public let md: String? + + private enum CodingKeys: String, CodingKey { + case order, termUrl = "TermUrl", url = "URL", md = "MD", paReq = "PaReq" + } +} + +// MARK: - OOS Error + +/// An error structure for OOS errors returned in flat JSON +/// `errorCode` and `errorDescription` +public struct ResponseError: Decodable { + + public let code: String + public let description: String? + + private enum CodingKeys: String, CodingKey { + case code = "errorCode" + case description = "errorDescription" + } + +} + +// MARK: - OOS Response + +/// JSON Response from OOS API +public struct Response: Decodable { + + public let status: ResponseStatus + public let requestId: String + public let error: ResponseError? + public let payment: ResponsePayment? + public let acquiringData: AcquiringResponseData? + public let description: String? + + private enum CodingKeys: String, CodingKey { + case status, requestId, payment, acquiringData, description + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.status = try container.decode(ResponseStatus.self, forKey: .status) + self.requestId = try container.decode(String.self, forKey: .requestId) + self.description = try? container.decode(String.self, forKey: .description) + + // Decode flat and nested data into nested structs + self.payment = try? container.decode(ResponsePayment.self, forKey: .payment) + self.acquiringData = try? AcquiringResponseData(from: decoder) + self.error = try? ResponseError(from: decoder) + } + +} + +// MARK: - Payment status +/// Payment stats +/// see: https://docs.pscb.ru/oos/index.html#obshaya-informaciya-spravochniki-statusy-platezhej +public enum PaymentState: String, Decodable { + case sent = "sent" + case new = "new" + case end = "end" + case refunded = "ref" + case hold = "hold" + case expired = "exp" + case canceled = "canceled" + case error = "error" + case rejected = "rej" + case undefined = "undef" +} + +// MARK: - Payment response struct +public struct ResponsePayment: Decodable { + public let orderId: String + public let showOrderId: String + public let paymentId: String + public let amount: Decimal + public let state: PaymentState + public let marketPlace: UInt16 + public let stateDate: Date +} diff --git a/PSCBOnline/Sources/PSCBAPI.swift b/PSCBOnline/Sources/PSCBAPI.swift new file mode 100644 index 0000000..83e04d6 --- /dev/null +++ b/PSCBOnline/Sources/PSCBAPI.swift @@ -0,0 +1,55 @@ +// +// OOSAPI.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 27.10.2020. +// + +import Foundation +import PassKit + +/// Utility fabric methods required for PSCB API. +public class PSCBAPI { + + public static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard] + + /// - Returns: a tuple describing if application `canMakePayments` and `canSetupCards` using supported networks. + public class func canMakePayments() -> (canMakePayments: Bool, canSetupCards: Bool) { + return ( + PKPaymentAuthorizationController.canMakePayments(), + PKPaymentAuthorizationController.canMakePayments(usingNetworks: supportedNetworks) + ) + } + + /// Creates a default instance of `PKPaymentRequest` with pre-default parameters. + /// + /// - Returns: `PKPaymentRequest` + public class func makePaymentRequest(items: [PKPaymentSummaryItem]) -> PKPaymentRequest { + return makePaymentRequest(merchantId: "merchant.pscb.pay", items: items) + } + + /// Creates a default instance of `PKPaymentRequest` with pre-default parameters. + /// + /// - Parameters: + /// - merchantId: Your Apple Pay merchant ID + /// - items: Summary items + /// + /// - Returns: `PKPaymentRequest` + public class func makePaymentRequest(merchantId: String, items: [PKPaymentSummaryItem]) -> PKPaymentRequest { + let request = PKPaymentRequest() + request.merchantIdentifier = merchantId + request.supportedNetworks = Self.supportedNetworks + + if #available(iOS 11.0, *) { + //request.supportedCountries = ["RU", "UA", "BY", "US"] + } + + request.merchantCapabilities = .capability3DS + request.countryCode = "RU" + request.currencyCode = "RUB" + request.paymentSummaryItems = items + + return request + } + +} diff --git a/PSCBOnline/Sources/PSCBOnlineClient.swift b/PSCBOnline/Sources/PSCBOnlineClient.swift new file mode 100644 index 0000000..95538fb --- /dev/null +++ b/PSCBOnline/Sources/PSCBOnlineClient.swift @@ -0,0 +1,306 @@ +// +// OOSAPIClient.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation +import PassKit + +// MARK: - Environments + +public enum BackendEnvironment: String { + + case production = "oos.pscb.ru" + case sandbox = "oosdemo.pscb.ru" + +} + +// MARK: - Request status + +/// Backend request status +/// Consists of two possible states: `.success` and `.failure`. +/// +/// This one represents if request to the backend server was successful +public enum RequestStatus { + case success, failure +} + +// MARK: - Response wrapper + +/// Backend response +public struct BackendResponse { + + /// Represents request status + public let status: RequestStatus + + /// Hold error information if request is a `.failure` + public let error: Error? + + /// Holds response information if request is a `.success` + public let response: Response? +} + +// MARK: - Alias for completion handler + +/// Callback for `OOSAPIClient.send` method +public typealias APICompletionHandler = (BackendResponse) -> Void + +/// Callback for another `OOSAPIClient.send` method which fires after certain guards ensure success or failure +/// to simplify API usage +public typealias PostResponseHandler = (Error?, Response?) -> Void + +// MARK: - API Integration errors + +/// Possible erros when dealing with OOS backend +public enum OOSErrors: Error { + case noData + case parse(Error) + case cause(Error) + + /// Consists of error code and error description + case backend(String, String) +} + +// MARK: - API Client + +/// Implementation of OOS Merchant API HTTP protocol. +final public class PSCBOnlineClient { + + private lazy var urlSession: URLSession = { + URLSession(configuration: .default, delegate: nil, delegateQueue: .main) + }() + + private lazy var url: URL = { + var components = URLComponents() + components.scheme = "https" + components.host = self.environment.rawValue + components.path = "/merchantApi/payShpa" + + return components.url! + }() + + private let decoder = JSONDecoders.iso8601DateAwareDecoder() + + // init: + + let environment: BackendEnvironment + let marketPlaceId: String + let signingKey: String + + /// Initializes `OOSAPIClient` + /// + /// - Parameters: + /// - environment: Backend environment. Which one to use. For testing environment use `.sandbox` + /// - marketPlaceId: Your OOS market-place ID + /// - siginingKey: Your OOS signing key + public init(environment: BackendEnvironment, marketPlaceId: String, signingKey: String) { + self.environment = environment + self.marketPlaceId = marketPlaceId + self.signingKey = signingKey + } + + // impl: + + /// Creates instance of `RequestWrapper` for a backend to process from given PKPayment instance and other details + /// + /// - Parameters: + /// - payment: authorized PKPayment instance + /// - amount: total order amount + /// - orderId: Unique merchant order ID + /// + /// - Returns: RequestWrapper instance for backend + public func makeRequestWithPayment(payment: PKPayment, amount: Decimal, orderId: String) throws -> RequestWrapper { + return try makeRequestWithPayment(pkPayment: payment, payment: Payment(amount: amount, orderId: orderId)) + } + + /// Creates instance of `RequestWrapper` for a backend to process from given `PKPayment` instance and backend `Payment` instance + /// + /// - Parameters: + /// - pkPayment: authorized `PKPayment` instance + /// - payment: backend `Payment` details + /// + /// - Returns: RequestWrapper instance for backend + public func makeRequestWithPayment(pkPayment: PKPayment, payment: Payment) throws -> RequestWrapper { + // Get card data cryptogram from payment token + let cardDataCrypto = try pkPayment.token.toCryptogramString() + + // Backend request wrapper + let requestWrapper = RequestWrapper( + marketPlaceId: self.marketPlaceId, + payment: payment, + cardData: cardDataCrypto + ) + + // Fail early + try requestWrapper.assumeSerializes() + + return requestWrapper + } + + /// Creates instance of `RequestWrapper` for a backend to process from raw card data instead of ApplePay token + /// + /// Example: + /// ``` + /// let card = CardData( + /// pan: "409444400001234", + /// expiryYear: 2025, + /// expiryMonth: 12, + /// cvCode: "000", + /// cardholder: "JOHN DOE" + /// ) + /// + /// let payment = Payment(amount: Decimal(1500), orderId: "XC-12345") + /// let request = try apiClient.createRequestWithCardData(card: card, payment: payment) + /// + /// // Send to backend: + /// apiClient.send(request) { (response) in /code/ } + /// ``` + /// + /// - Parameters: + /// - cardData: an instance of card data. + public func makeRequestWithCardData(card: CardData, payment: Payment) throws -> RequestWrapper { + let cryptogram = try card.toCryptgramString() + let request = RequestWrapper( + marketPlaceId: self.marketPlaceId, + payment: payment, + cardData: cryptogram + ) + + // Fail-early compile + try request.assumeSerializes() + + return request + } + + /// Signs and sends compiled `RequestWrapper` to the backend server + /// Fires `APICompletionHandler` once requests succeeds or fails + /// + /// - Parameters: + /// - request: `RequestWrapper` created from `createRequestWithPayment(...)` + /// - completionHander: `APICompletionHandler` a callback for when requests succeeds or fails + /// + public func send(_ request: RequestWrapper, completionHandler: @escaping APICompletionHandler) { + // Calculate signature and get HTTP body at the same time + let httpBody = try! request.serializeToString() + let signature = calculateSignature(httpBody) + + // Request params + let url = self.url + var req = URLRequest(url: url) + + // Set request parameters + req.httpMethod = "POST" + req.httpBody = httpBody.data(using: .utf8) + req.setValue(signature, forHTTPHeaderField: "Signature") + + print(">> Request JSON: \(String(describing: String(data: req.httpBody!, encoding: .utf8)))") + + let task = urlSession.dataTask(with: req) { (data, res, err) in + guard err == nil else { + let error = self.err_requestError(req, error: err) + completionHandler(error) + return + } + + guard let data = data else { + let error = self.failure(req, error: OOSErrors.noData) + completionHandler(error) + return + } + + print("<< Response data: \(String(data: data, encoding: .utf8) ?? "N/A")") + + do { + let response = try self.decoder.decode(Response.self, from: data) + + // Finaly success + let success = BackendResponse(status: .success, error: nil, response: response) + + completionHandler(success) + } catch let error { + print("Failed to do task on request \(req)") + print(error.localizedDescription) + + // Reading and parsing errors + let failure = self.failure(req, error: .parse(error)) + completionHandler(failure) + } + + } + + // Fire task + task.resume() + } + + /// Signs and sends compiled `RequestWrapper` to the backend server + /// Fires `PostResponseHandler` once requests succeeds or fails. + /// `PostResponseHandler` accepts two arguments: `Error?` and `Response?`. + /// + /// If requests succeeds and payment in desired state `Error?` will always be `nil`. + /// `Response?` presents on some errors and on all successes. + /// + /// This is an utility method to reduce boilerplate for necessary checks. + /// + /// - Parameters: + /// - request: `RequestWrapper` created from `createRequestWithPayment(...)` + /// - completionHander: `APICompletionHandler` a callback for when requests succeeds or fails + /// + public func send(_ request: RequestWrapper, responseHandler: @escaping PostResponseHandler) { + // Construct a closure wrapper with predefined guards and checks + let wrapper: APICompletionHandler = { (backendResponse) in + // HTTP request succeeded? + guard backendResponse.status == .success else { + print("Failed to execute request due to error: \(String(describing: backendResponse.error))") + + responseHandler(OOSErrors.cause(backendResponse.error!), nil) + return + } + + // Backend returned valid response? + guard let response = backendResponse.response else { + print("Backend returned empty body") + + responseHandler(OOSErrors.noData, nil) + return + } + + // Backend payment succeeded? + guard response.status == .success else { + print("Unable to process payment") + + let responseError = response.error + let backendError = OOSErrors.backend(responseError?.code ?? "FAILED", responseError?.description ?? "") + + // At this point we can pass response too + responseHandler(backendError, response) + return + } + + // Finally succeeds + responseHandler(nil, response) + } + + // Send using more lower-level method above + send(request, completionHandler: wrapper) + } + + // MARK: - Private + + private func err_requestError(_ req: URLRequest, error: Error?) -> BackendResponse { + print("Failed to do task on request \(req) with error: \(String(describing: error))") + return BackendResponse(status: .failure, error: OOSErrors.cause(error!), response: nil) + } + + private func failure(_ req: URLRequest, error: OOSErrors) -> BackendResponse { + print("Request \(req) failed with error: \(String(describing: error))") + return BackendResponse(status: .failure, error: error, response: nil) + } + + private func calculateSignature(_ jsonString: String) -> String { + let composite = (jsonString + self.signingKey) + return DigestHelper.sha256String(composite) + } + +} diff --git a/PSCBOnline/Sources/PaymentHandler.swift b/PSCBOnline/Sources/PaymentHandler.swift new file mode 100644 index 0000000..a6bad97 --- /dev/null +++ b/PSCBOnline/Sources/PaymentHandler.swift @@ -0,0 +1,113 @@ +// +// PaymentHandler.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 16.10.2020. +// + +import Foundation +import PassKit + +public typealias PaymentCompletionHandler = (Bool) -> Void + +public class ApplePayHandler: NSObject { + + static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard] + + // MARK: - Fields + + public let merchantId: String + public let merchantKey: String + public let summaryItems: [PKPaymentSummaryItem] + + // MARK: - Properties + + var paymentController: PKPaymentAuthorizationController? + var paymentStatus: PKPaymentAuthorizationStatus = .failure + var completionHandler: PaymentCompletionHandler? + var payment: Payment? + + public init?(merchantId: String, merchantKey: String, summaryItems: [PKPaymentSummaryItem]) { + guard PKPaymentAuthorizationController.canMakePayments(usingNetworks: Self.supportedNetworks) else { + print("Could not instantiate ApplePayHandler. Cannot make payments with provided networks") + return nil + } + + self.merchantId = merchantId + self.merchantKey = merchantKey + self.summaryItems = summaryItems + } + + public func handle(payment: Payment, completion: @escaping PaymentCompletionHandler) { + self.completionHandler = completion + self.payment = payment + + NSLog("About to handle payment: \(payment)") + + paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest) + paymentController?.delegate = self + paymentController?.present { (presented) in + if !presented { + NSLog("Could not present PKPaymentAuthorizationController") + self.completionHandler!(false) + } else { + NSLog("PKPaymentAuthorizationController presented") + } + } + + } + + // MARK: - Private details + + private var paymentRequest: PKPaymentRequest { + let request = PKPaymentRequest() + + request.countryCode = "RU" + request.merchantIdentifier = "merchant.pscb.pay" + request.currencyCode = "RUB" + request.supportedNetworks = Self.supportedNetworks + request.merchantCapabilities = .capability3DS + request.paymentSummaryItems = summaryItems + + return request + } + +} + + +// MARK: - Extension for PKPaymentAuthorizationControllerDelegate + +extension ApplePayHandler: PKPaymentAuthorizationControllerDelegate { + + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, + didAuthorizePayment payment: PKPayment, + completion: @escaping (PKPaymentAuthorizationStatus) -> Void) { + +// print("Payment string") +// let paymentString = try! payment.serializeToString() +// print(paymentString) +// +// // +// +// self.paymentStatus = .success + completion(PKPaymentAuthorizationStatus.success) + } + + @available(iOS 11.0, *) + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { +// +// NSLog("About to send request to backend") +// let paymentString = try! payment.serializeToString() +// +// NSLog("Payment JSON: \(paymentString)") +// + let result = PKPaymentAuthorizationResult(status: .success, errors: nil) + completion(result) + self.completionHandler?(true) + } + + public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { + controller.dismiss(completion: nil) + } + +} diff --git a/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift b/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift new file mode 100644 index 0000000..a64bacd --- /dev/null +++ b/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift @@ -0,0 +1,79 @@ +// +// PKPaymentToken+Serializable.swift +// PSCB-OOS-iOS +// +// Created by OA on 17.10.2020. +// + +import Foundation +import PassKit + +// MARK: - Comfront to serializable +extension PKPaymentToken: Serializable { + + // Serializes token to a JSONLike dictionary + public func serializeToJSON() -> JSONDict { + let paymentJson: JSONDict? = try? JSONSerialization.jsonObject( + with: self.paymentData, options: .mutableContainers + ) as? JSONDict + + var paymentType: String = "debit" + var methodAndNetwork: JSONDict = [ + "network": "", + "type": paymentType, + "displayName": "" + ] + + if #available(iOS 9.0, *) { + methodAndNetwork = [ + "network": self.paymentMethod.network?.rawValue ?? "", + "type": paymentType, + "displayName": self.paymentMethod.displayName ?? "" + ] + + switch self.paymentMethod.type { + case .debit: + paymentType = "debit" + case .credit: + paymentType = "credit" + case .store: + paymentType = "store" + case .prepaid: + paymentType = "prepaid" + default: + paymentType = "unknown" + } + } + + return [ + "paymentData": paymentJson, + "transactionIdentifier": self.transactionIdentifier, + "paymentMethod": methodAndNetwork + ] as JSONDict + } + +} + +// MARK: - To string cryptogram +extension PKPaymentToken { + + private func paymentJSONData() -> JSONDict? { + let json = self.serializeToJSON() + let data = json["paymentData"] as! JSONDict? + + return data + } + + /// Creates a Base64 encoded cryptogram string accepted by PSCB OOS protocol + /// May throw JSON serialization errors if token could not be converted to JSON string before writing a cryptogram. + /// + /// - Returns: Base64 encoded string + public func toCryptogramString() throws -> String { + let json = self.paymentJSONData() + let data = try JSONSerialization.data(withJSONObject: json!, options: []) + // let string = String(data: data, encoding: .utf8)! + + return data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)) + } + +} diff --git a/PSCBOnline/Sources/Serializable/Payment+Serializable.swift b/PSCBOnline/Sources/Serializable/Payment+Serializable.swift new file mode 100644 index 0000000..74767bd --- /dev/null +++ b/PSCBOnline/Sources/Serializable/Payment+Serializable.swift @@ -0,0 +1,27 @@ +// +// Payment+Serializable.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 21.10.2020. +// + +import Foundation + +extension Payment: Serializable { + + public func serializeToJSON() -> JSONDict { + var json = JSONDict() + json["orderId"] = self.orderId + json["amount"] = self.amount + json["showOrderId"] = self.showOrderId + json["details"] = self.details + json["recurrentable"] = self.recurrentable + json["customerAccount"] = self.customer?.account + json["customerComment"] = self.customer?.comment + json["customerEmail"] = self.customer?.email + json["customerPhone"] = self.customer?.phone + + return json + } + +} diff --git a/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift b/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift new file mode 100644 index 0000000..25a1bdf --- /dev/null +++ b/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift @@ -0,0 +1,21 @@ +// +// RequestWrapper+Serializable.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 18.10.2020. +// + +import Foundation + +extension RequestWrapper: Serializable { + + public func serializeToJSON() -> JSONDict { + var json = JSONDict() + json["marketPlace"] = self.marketPlaceId + json["payment"] = self.payment.serializeToJSON() + json["cardData"] = self.cardData + + return json + } + +} diff --git a/PSCBOnline/Sources/Serializable/Serializable.swift b/PSCBOnline/Sources/Serializable/Serializable.swift new file mode 100644 index 0000000..520de98 --- /dev/null +++ b/PSCBOnline/Sources/Serializable/Serializable.swift @@ -0,0 +1,61 @@ +// +// Serializable.swift +// PSCB-OOS-iOS +// +// Created by OA on 16.10.2020. +// + +import Foundation + +// MARK: - Serializable + +public protocol Serializable { + + /// Serializes current object to generic JSON-Like dictionary + func serializeToJSON() -> JSONDict + +} + +// MARK: - Extension + +public extension Serializable { + + /// Serializes current object to data + func serializeToData() throws -> Data { +// let encoder = JSONEncoder() +// let data = try encoder.encode(self.serializeToJSON()) +// +// return data + return try JSONSerialization.data( + withJSONObject: self.serializeToJSON(), + options: [] + ) + } + + /// Serialzes to JSON-String + func serializeToString() throws -> String { + let data = try self.serializeToData() + return String(data: data, encoding: .utf8)! + } + + /// Used for checking purposes if this object can be serialized without exception + func assumeSerializes() throws { + try serializeToString() + } + +} + +// MARK: - JSONDict + +public typealias JSONDict = [AnyHashable: AnyHashable] + +//extension JSONDict { +// +// public mutating func add(key: T, nullable value: JSONDict.Value?) where T.RawValue == JSONDict.Key { +// if let value = value { +// self.updateValue(value, forKey: key.rawValue) +// } +// } +// +//} + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.pbxproj b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bb8c6f7 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.pbxproj @@ -0,0 +1,762 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 001B6B6B8EAA1CC9E76C93F2 /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 215AD129A382ED26BE4A9ADC /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */; }; + 0ECA01D9254C88BF003DBD74 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA01D8254C88BF003DBD74 /* AppDelegate.swift */; }; + 0ECA01DB254C88BF003DBD74 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA01DA254C88BF003DBD74 /* SceneDelegate.swift */; }; + 0ECA01DD254C88BF003DBD74 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA01DC254C88BF003DBD74 /* ContentView.swift */; }; + 0ECA01DF254C88C4003DBD74 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0ECA01DE254C88C4003DBD74 /* Assets.xcassets */; }; + 0ECA01E2254C88C4003DBD74 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0ECA01E1254C88C4003DBD74 /* Preview Assets.xcassets */; }; + 0ECA01E5254C88C4003DBD74 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ECA01E3254C88C4003DBD74 /* LaunchScreen.storyboard */; }; + 0ECA01F0254C88C5003DBD74 /* sdk_sampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA01EF254C88C5003DBD74 /* sdk_sampleTests.swift */; }; + 0ECA01FB254C88C5003DBD74 /* sdk_sampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA01FA254C88C5003DBD74 /* sdk_sampleUITests.swift */; }; + 0ECA0218254C8C12003DBD74 /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = 0ECA0217254C8C12003DBD74 /* Podfile */; }; + 0ECA0237254C8DA0003DBD74 /* PaymentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA0236254C8DA0003DBD74 /* PaymentHandler.swift */; }; + 37FA89195E22BD0C552D887A /* Pods_PSCBOnlineSampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75E713AE69B50BE64C2D03E8 /* Pods_PSCBOnlineSampleTests.framework */; }; + 69E05BEE77EA2E75B91678EE /* Pods_PSCBOnlineSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADAE0E73DFA819AE992A9C59 /* Pods_PSCBOnlineSample.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0ECA01EC254C88C5003DBD74 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0ECA01CD254C88BF003DBD74 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0ECA01D4254C88BF003DBD74; + remoteInfo = sdk.sample; + }; + 0ECA01F7254C88C5003DBD74 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0ECA01CD254C88BF003DBD74 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0ECA01D4254C88BF003DBD74; + remoteInfo = sdk.sample; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0ECA01D5254C88BF003DBD74 /* PSCBOnlineSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PSCBOnlineSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0ECA01D8254C88BF003DBD74 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0ECA01DA254C88BF003DBD74 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 0ECA01DC254C88BF003DBD74 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 0ECA01DE254C88C4003DBD74 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0ECA01E1254C88C4003DBD74 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 0ECA01E4254C88C4003DBD74 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 0ECA01E6254C88C4003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0ECA01EB254C88C5003DBD74 /* PSCBOnlineSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PSCBOnlineSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0ECA01EF254C88C5003DBD74 /* sdk_sampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sdk_sampleTests.swift; sourceTree = ""; }; + 0ECA01F1254C88C5003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0ECA01F6254C88C5003DBD74 /* PSCBOnlineSampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PSCBOnlineSampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0ECA01FA254C88C5003DBD74 /* sdk_sampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sdk_sampleUITests.swift; sourceTree = ""; }; + 0ECA01FC254C88C5003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0ECA020B254C8902003DBD74 /* sdk.sample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = sdk.sample.entitlements; sourceTree = ""; }; + 0ECA0217254C8C12003DBD74 /* Podfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 0ECA0236254C8DA0003DBD74 /* PaymentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentHandler.swift; sourceTree = ""; }; + 215AD129A382ED26BE4A9ADC /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2EAAA258959A1F5D92CFD851 /* Pods-PSCBOnlineSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSample.release.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.release.xcconfig"; sourceTree = ""; }; + 3E1FFD5E11C6E53BAB8BDD2B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig"; sourceTree = ""; }; + 597562929002737E312BE5A9 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig"; sourceTree = ""; }; + 5D25A9250438F9C8AA6153F8 /* Pods-PSCBOnlineSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSample.debug.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.debug.xcconfig"; sourceTree = ""; }; + 75E713AE69B50BE64C2D03E8 /* Pods_PSCBOnlineSampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PSCBOnlineSampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + ADAE0E73DFA819AE992A9C59 /* Pods_PSCBOnlineSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PSCBOnlineSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AE94091A3CE7B540776F6146 /* Pods-PSCBOnlineSampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSampleTests.release.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.release.xcconfig"; sourceTree = ""; }; + EE4EA7D50047330E553B55B6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PSCBOnlineSampleTests.debug.xcconfig"; path = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0ECA01D2254C88BF003DBD74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 69E05BEE77EA2E75B91678EE /* Pods_PSCBOnlineSample.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01E8254C88C5003DBD74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 37FA89195E22BD0C552D887A /* Pods_PSCBOnlineSampleTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01F3254C88C5003DBD74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 001B6B6B8EAA1CC9E76C93F2 /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0ECA01CC254C88BF003DBD74 = { + isa = PBXGroup; + children = ( + 0ECA0217254C8C12003DBD74 /* Podfile */, + 0ECA01D7254C88BF003DBD74 /* PSCBOnlineSample */, + 0ECA01EE254C88C5003DBD74 /* PSCBOnlineSampleTests */, + 0ECA01F9254C88C5003DBD74 /* PSCBOnlineSampleUITests */, + 0ECA01D6254C88BF003DBD74 /* Products */, + A6BE523F775C844325774B50 /* Pods */, + CC92252B44ABB68C5546B8DC /* Frameworks */, + ); + sourceTree = ""; + }; + 0ECA01D6254C88BF003DBD74 /* Products */ = { + isa = PBXGroup; + children = ( + 0ECA01D5254C88BF003DBD74 /* PSCBOnlineSample.app */, + 0ECA01EB254C88C5003DBD74 /* PSCBOnlineSampleTests.xctest */, + 0ECA01F6254C88C5003DBD74 /* PSCBOnlineSampleUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0ECA01D7254C88BF003DBD74 /* PSCBOnlineSample */ = { + isa = PBXGroup; + children = ( + 0ECA020B254C8902003DBD74 /* sdk.sample.entitlements */, + 0ECA01D8254C88BF003DBD74 /* AppDelegate.swift */, + 0ECA01DA254C88BF003DBD74 /* SceneDelegate.swift */, + 0ECA01DC254C88BF003DBD74 /* ContentView.swift */, + 0ECA01DE254C88C4003DBD74 /* Assets.xcassets */, + 0ECA01E3254C88C4003DBD74 /* LaunchScreen.storyboard */, + 0ECA01E6254C88C4003DBD74 /* Info.plist */, + 0ECA01E0254C88C4003DBD74 /* Preview Content */, + 0ECA0236254C8DA0003DBD74 /* PaymentHandler.swift */, + ); + path = PSCBOnlineSample; + sourceTree = ""; + }; + 0ECA01E0254C88C4003DBD74 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 0ECA01E1254C88C4003DBD74 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 0ECA01EE254C88C5003DBD74 /* PSCBOnlineSampleTests */ = { + isa = PBXGroup; + children = ( + 0ECA01EF254C88C5003DBD74 /* sdk_sampleTests.swift */, + 0ECA01F1254C88C5003DBD74 /* Info.plist */, + ); + path = PSCBOnlineSampleTests; + sourceTree = ""; + }; + 0ECA01F9254C88C5003DBD74 /* PSCBOnlineSampleUITests */ = { + isa = PBXGroup; + children = ( + 0ECA01FA254C88C5003DBD74 /* sdk_sampleUITests.swift */, + 0ECA01FC254C88C5003DBD74 /* Info.plist */, + ); + path = PSCBOnlineSampleUITests; + sourceTree = ""; + }; + A6BE523F775C844325774B50 /* Pods */ = { + isa = PBXGroup; + children = ( + 5D25A9250438F9C8AA6153F8 /* Pods-PSCBOnlineSample.debug.xcconfig */, + 2EAAA258959A1F5D92CFD851 /* Pods-PSCBOnlineSample.release.xcconfig */, + 597562929002737E312BE5A9 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */, + 3E1FFD5E11C6E53BAB8BDD2B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */, + EE4EA7D50047330E553B55B6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */, + AE94091A3CE7B540776F6146 /* Pods-PSCBOnlineSampleTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + CC92252B44ABB68C5546B8DC /* Frameworks */ = { + isa = PBXGroup; + children = ( + ADAE0E73DFA819AE992A9C59 /* Pods_PSCBOnlineSample.framework */, + 215AD129A382ED26BE4A9ADC /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */, + 75E713AE69B50BE64C2D03E8 /* Pods_PSCBOnlineSampleTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0ECA01D4254C88BF003DBD74 /* PSCBOnlineSample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0ECA01FF254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSample" */; + buildPhases = ( + CD6C55176C28DD5EC847748D /* [CP] Check Pods Manifest.lock */, + 0ECA01D1254C88BF003DBD74 /* Sources */, + 0ECA01D2254C88BF003DBD74 /* Frameworks */, + 0ECA01D3254C88BF003DBD74 /* Resources */, + 1CCC3026FF4B068D24933916 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PSCBOnlineSample; + productName = sdk.sample; + productReference = 0ECA01D5254C88BF003DBD74 /* PSCBOnlineSample.app */; + productType = "com.apple.product-type.application"; + }; + 0ECA01EA254C88C5003DBD74 /* PSCBOnlineSampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0ECA0202254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSampleTests" */; + buildPhases = ( + 143B1BD2DA6C604E39332B78 /* [CP] Check Pods Manifest.lock */, + 0ECA01E7254C88C5003DBD74 /* Sources */, + 0ECA01E8254C88C5003DBD74 /* Frameworks */, + 0ECA01E9254C88C5003DBD74 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0ECA01ED254C88C5003DBD74 /* PBXTargetDependency */, + ); + name = PSCBOnlineSampleTests; + productName = sdk.sampleTests; + productReference = 0ECA01EB254C88C5003DBD74 /* PSCBOnlineSampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 0ECA01F5254C88C5003DBD74 /* PSCBOnlineSampleUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0ECA0205254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSampleUITests" */; + buildPhases = ( + A1AABD89A7AA5EFA1FDE3606 /* [CP] Check Pods Manifest.lock */, + 0ECA01F2254C88C5003DBD74 /* Sources */, + 0ECA01F3254C88C5003DBD74 /* Frameworks */, + 0ECA01F4254C88C5003DBD74 /* Resources */, + 6BAD522C988953C7BFCC5A17 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 0ECA01F8254C88C5003DBD74 /* PBXTargetDependency */, + ); + name = PSCBOnlineSampleUITests; + productName = sdk.sampleUITests; + productReference = 0ECA01F6254C88C5003DBD74 /* PSCBOnlineSampleUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0ECA01CD254C88BF003DBD74 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1210; + LastUpgradeCheck = 1210; + TargetAttributes = { + 0ECA01D4254C88BF003DBD74 = { + CreatedOnToolsVersion = 12.1; + }; + 0ECA01EA254C88C5003DBD74 = { + CreatedOnToolsVersion = 12.1; + TestTargetID = 0ECA01D4254C88BF003DBD74; + }; + 0ECA01F5254C88C5003DBD74 = { + CreatedOnToolsVersion = 12.1; + TestTargetID = 0ECA01D4254C88BF003DBD74; + }; + }; + }; + buildConfigurationList = 0ECA01D0254C88BF003DBD74 /* Build configuration list for PBXProject "PSCBOnlineSample" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0ECA01CC254C88BF003DBD74; + productRefGroup = 0ECA01D6254C88BF003DBD74 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0ECA01D4254C88BF003DBD74 /* PSCBOnlineSample */, + 0ECA01EA254C88C5003DBD74 /* PSCBOnlineSampleTests */, + 0ECA01F5254C88C5003DBD74 /* PSCBOnlineSampleUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0ECA01D3254C88BF003DBD74 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0ECA01E5254C88C4003DBD74 /* LaunchScreen.storyboard in Resources */, + 0ECA01E2254C88C4003DBD74 /* Preview Assets.xcassets in Resources */, + 0ECA0218254C8C12003DBD74 /* Podfile in Resources */, + 0ECA01DF254C88C4003DBD74 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01E9254C88C5003DBD74 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01F4254C88C5003DBD74 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 143B1BD2DA6C604E39332B78 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PSCBOnlineSampleTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 1CCC3026FF4B068D24933916 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 6BAD522C988953C7BFCC5A17 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A1AABD89A7AA5EFA1FDE3606 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + CD6C55176C28DD5EC847748D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PSCBOnlineSample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0ECA01D1254C88BF003DBD74 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0ECA01D9254C88BF003DBD74 /* AppDelegate.swift in Sources */, + 0ECA01DB254C88BF003DBD74 /* SceneDelegate.swift in Sources */, + 0ECA01DD254C88BF003DBD74 /* ContentView.swift in Sources */, + 0ECA0237254C8DA0003DBD74 /* PaymentHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01E7254C88C5003DBD74 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0ECA01F0254C88C5003DBD74 /* sdk_sampleTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0ECA01F2254C88C5003DBD74 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0ECA01FB254C88C5003DBD74 /* sdk_sampleUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0ECA01ED254C88C5003DBD74 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0ECA01D4254C88BF003DBD74 /* PSCBOnlineSample */; + targetProxy = 0ECA01EC254C88C5003DBD74 /* PBXContainerItemProxy */; + }; + 0ECA01F8254C88C5003DBD74 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0ECA01D4254C88BF003DBD74 /* PSCBOnlineSample */; + targetProxy = 0ECA01F7254C88C5003DBD74 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 0ECA01E3254C88C4003DBD74 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0ECA01E4254C88C4003DBD74 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0ECA01FD254C88C5003DBD74 /* 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 0ECA01FE254C88C5003DBD74 /* 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0ECA0200254C88C5003DBD74 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5D25A9250438F9C8AA6153F8 /* Pods-PSCBOnlineSample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"PSCBOnlineSample/Preview Content\""; + DEVELOPMENT_TEAM = 46N426YCGP; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = PSCBOnlineSample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.ios-lib-sample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0ECA0201254C88C5003DBD74 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2EAAA258959A1F5D92CFD851 /* Pods-PSCBOnlineSample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"PSCBOnlineSample/Preview Content\""; + DEVELOPMENT_TEAM = 46N426YCGP; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = PSCBOnlineSample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.ios-lib-sample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 0ECA0203254C88C5003DBD74 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EE4EA7D50047330E553B55B6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineSampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.sdk-sampleTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PSCBOnlineSample.app/PSCBOnlineSample"; + }; + name = Debug; + }; + 0ECA0204254C88C5003DBD74 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE94091A3CE7B540776F6146 /* Pods-PSCBOnlineSampleTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineSampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.sdk-sampleTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PSCBOnlineSample.app/PSCBOnlineSample"; + }; + name = Release; + }; + 0ECA0206254C88C5003DBD74 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 597562929002737E312BE5A9 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineSampleUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.sdk-sampleUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = sdk.sample; + }; + name = Debug; + }; + 0ECA0207254C88C5003DBD74 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E1FFD5E11C6E53BAB8BDD2B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46N426YCGP; + INFOPLIST_FILE = PSCBOnlineSampleUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "ru.pscb.sdk-sampleUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = sdk.sample; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0ECA01D0254C88BF003DBD74 /* Build configuration list for PBXProject "PSCBOnlineSample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0ECA01FD254C88C5003DBD74 /* Debug */, + 0ECA01FE254C88C5003DBD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0ECA01FF254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0ECA0200254C88C5003DBD74 /* Debug */, + 0ECA0201254C88C5003DBD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0ECA0202254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0ECA0203254C88C5003DBD74 /* Debug */, + 0ECA0204254C88C5003DBD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0ECA0205254C88C5003DBD74 /* Build configuration list for PBXNativeTarget "PSCBOnlineSampleUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0ECA0206254C88C5003DBD74 /* Debug */, + 0ECA0207254C88C5003DBD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0ECA01CD254C88BF003DBD74 /* Project object */; +} diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..05f84ea Binary files /dev/null and b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/project.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcshareddata/xcschemes/PSCBOnlineSample.xcscheme b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcshareddata/xcschemes/PSCBOnlineSample.xcscheme new file mode 100644 index 0000000..c4d779e --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcshareddata/xcschemes/PSCBOnlineSample.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..fb70a58 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,37 @@ + + + + + SchemeUserState + + PSCBOnlineSample.xcscheme_^#shared#^_ + + orderHint + 0 + + sdk.sample.xcscheme_^#shared#^_ + + orderHint + 4 + + + SuppressBuildableAutocreation + + 0ECA01D4254C88BF003DBD74 + + primary + + + 0ECA01EA254C88C5003DBD74 + + primary + + + 0ECA01F5254C88C5003DBD74 + + primary + + + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/contents.xcworkspacedata b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d258a81 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..27c11fd Binary files /dev/null and b/PSCBOnlineSample/PSCBOnlineSample.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/PSCBOnlineSample/PSCBOnlineSample/AppDelegate.swift b/PSCBOnlineSample/PSCBOnlineSample/AppDelegate.swift new file mode 100644 index 0000000..e0d05f7 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// sdk.sample +// +// Created by OA on 30.10.2020. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AccentColor.colorset/Contents.json b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AppIcon.appiconset/Contents.json b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/Contents.json b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/Base.lproj/LaunchScreen.storyboard b/PSCBOnlineSample/PSCBOnlineSample/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample/ContentView.swift b/PSCBOnlineSample/PSCBOnlineSample/ContentView.swift new file mode 100644 index 0000000..3c1c9f7 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/ContentView.swift @@ -0,0 +1,124 @@ +// +// ContentView.swift +// sdk.sample +// +// Created by Antonov Ilia on 30.10.2020. +// + +import SwiftUI +import PassKit +import PSCBOnline + +struct ContentView: View { + + static let dateFormatter: DateFormatter = { + let df = DateFormatter() + df.dateFormat = "yyMMddhhmmss" + + return df + }() + + let paymentMethods = ["Apple pay", "Credit Card"] + let amount = Decimal(155.35) + let handler = PaymentHandler() + + @State private var paymentMethod = 0 + @State private var showAlert = false + @State private var paymentState: PaymentStatus = .unknown + @State private var lastOrderId: String? + + var body: some View { + VStack { + if (self.lastOrderId != nil) { + Text("Last order ID = \(self.lastOrderId!)") + } else { + Text("No payments has been made yet") + } + + Picker(selection: $paymentMethod, label: Text("Which way would you like to pay?")) { + ForEach(0 ..< paymentMethods.count) { + Text(self.paymentMethods[$0]) + } + } + + Button(action: { + self.handlePayment() + }) { + HStack { + Text("Pay!") + .fontWeight(.semibold) + .font(.title) + } + .frame(minWidth: 0, maxWidth: .infinity) + .padding() + .foregroundColor(.white) + .background(Color(.black)) + .cornerRadius(40) + .alert(isPresented: self.$showAlert, content: { + Alert( + title: Text("Payment status"), + message: Text("\(String(describing: self.paymentState))"), + dismissButton: .default(Text("OK")) + ) + }) + } + } + } + + func handlePayment() { + let now = Self.dateFormatter.string(from: Date()) + + // Payment info + let payment = Payment(amount: self.amount, orderId: "XC-\(now)") + + if (self.paymentMethod == 0) { + payByApplePay(payment) + } + + if (self.paymentMethod == 1) { + payByCreditCard(payment) + } + } + + private func payByApplePay(_ payment: Payment) { + let item = PKPaymentSummaryItem( + label: "Sample", + amount: NSDecimalNumber(decimal: self.amount) + ) + + self.handler.applePay(payment, items: [item]) { (status) in + if status == .success { + self.lastOrderId = payment.orderId + print("Meow") + } else { + print("ArghhH!") + } + } + } + + private func payByCreditCard(_ payment: Payment) { + // Card info + let card = CardData( + pan: "4761 1200 10000492", + expiryYear: 2022, + expiryMonth: 11, + cvCode: "533" + ) + + self.handler.creditCard( + payment, + card: card!, + completionHandler: { (status) in + self.showAlert = true + self.paymentState = status + print("Success?: \(status)") + }) + } + +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/Info.plist b/PSCBOnlineSample/PSCBOnlineSample/Info.plist new file mode 100644 index 0000000..2688b32 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Info.plist @@ -0,0 +1,62 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/PSCBOnlineSample/PSCBOnlineSample/PaymentHandler.swift b/PSCBOnlineSample/PSCBOnlineSample/PaymentHandler.swift new file mode 100644 index 0000000..9ef5846 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/PaymentHandler.swift @@ -0,0 +1,129 @@ +// +// PaymentHandler.swift +// sdk.sample +// +// Created by Antonov Ilia on 30.10.2020. +// + +import Foundation +import PassKit +import PSCBOnline + +// MARK: - Payment status +public enum PaymentStatus { + case success + case failure + case unknown +} + +public typealias PaymentCompletionHandler = (PaymentStatus) -> Void + +// MARK: - Payment hander +public class PaymentHandler: NSObject { + + // Initialize OOS API Client + static let client = PSCBOnlineClient(environment: .sandbox, marketPlaceId: "288747332", signingKey: "111111") + + // Current payment status + private var paymentStatus: PaymentStatus = .unknown + private var completionHandler: PaymentCompletionHandler? + + private var authorizationController: PKPaymentAuthorizationController? + private var payment: Payment? + + // MARK: - Payment handlers + func applePay(_ payment: Payment, items: [PKPaymentSummaryItem], + completionHandler: @escaping PaymentCompletionHandler) { + let status = PSCBAPI.canMakePayments() + print("status: \(String(describing: status))") + + // Create PKPayment instance + let pk = PSCBAPI.makePaymentRequest(items: items) + + self.completionHandler = completionHandler + self.payment = payment + + authorizationController = PKPaymentAuthorizationController(paymentRequest: pk) + authorizationController?.delegate = self + authorizationController?.present(completion: { presented in + if presented { + print("Controller presented") + } else { + print("Controller could not be presented") + completionHandler(.unknown) + } + }) + } + + func creditCard(_ payment: Payment, card: CardData, + completionHandler: @escaping PaymentCompletionHandler) { + let client = Self.client + + do { + // Create request token + let request = try client.makeRequestWithCardData(card: card, payment: payment) + + // Send request to backend + client.send(request, responseHandler: { (error, response) in + guard nil == error else { + print("Error sending request: \(String(describing: error))") + + completionHandler(.failure) + return + } + + print("Successful request:") + print(response!) + + completionHandler(.success) + }) + } catch { + print("Unable to create request: \(String(describing: error))") + completionHandler(.failure) + } + } + +} + +// MARK: - Conforming to PKPaymentAuthorizationControllerDelegate +extension PaymentHandler: PKPaymentAuthorizationControllerDelegate { + + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, + didAuthorizePayment payment: PKPayment, + handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { + // Payment authorized. Make request to backend + // Create request token + let request = try! Self.client.makeRequestWithPayment(pkPayment: payment, payment: self.payment!) + + Self.client.send(request, responseHandler: { (error, response) in + if (error == nil && response != nil) { + self.paymentStatus = .success + + completion(PKPaymentAuthorizationResult(status: .success, errors: nil)) + } else { + print("Error sending payment: \(String(describing: error))") + self.paymentStatus = .failure + + completion(PKPaymentAuthorizationResult(status: .failure, errors: nil)) + } + + self.completionHandler!(self.paymentStatus) + }) + } + + public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { + controller.dismiss { + DispatchQueue.main.async { + print("Did finish with status: \(self.paymentStatus)") + if self.paymentStatus == .success { + self.completionHandler!(.success) + } else { + self.completionHandler!(.failure) + } + + self.paymentStatus = .unknown + } + } + } + +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/Preview Content/Preview Assets.xcassets/Contents.json b/PSCBOnlineSample/PSCBOnlineSample/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PSCBOnlineSample/PSCBOnlineSample/SceneDelegate.swift b/PSCBOnlineSample/PSCBOnlineSample/SceneDelegate.swift new file mode 100644 index 0000000..b759199 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/SceneDelegate.swift @@ -0,0 +1,63 @@ +// +// SceneDelegate.swift +// sdk.sample +// +// Created by OA on 30.10.2020. +// + +import UIKit +import SwiftUI + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + + // Create the SwiftUI view that provides the window contents. + let contentView = ContentView() + + // Use a UIHostingController as window root view controller. + if let windowScene = scene as? UIWindowScene { + let window = UIWindow(windowScene: windowScene) + window.rootViewController = UIHostingController(rootView: contentView) + self.window = window + window.makeKeyAndVisible() + } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily 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/PSCBOnlineSample/PSCBOnlineSample/sdk.sample.entitlements b/PSCBOnlineSample/PSCBOnlineSample/sdk.sample.entitlements new file mode 100644 index 0000000..5ed1a01 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSample/sdk.sample.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.developer.associated-domains + + com.apple.developer.in-app-payments + + merchant.pscb.pay + + + diff --git a/PSCBOnlineSample/PSCBOnlineSampleTests/Info.plist b/PSCBOnlineSample/PSCBOnlineSampleTests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSampleTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/PSCBOnlineSample/PSCBOnlineSampleTests/sdk_sampleTests.swift b/PSCBOnlineSample/PSCBOnlineSampleTests/sdk_sampleTests.swift new file mode 100644 index 0000000..ee3d01b --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSampleTests/sdk_sampleTests.swift @@ -0,0 +1,33 @@ +// +// sdk_sampleTests.swift +// sdk.sampleTests +// +// Created by OA on 30.10.2020. +// + +import XCTest +@testable import sdk_sample + +class sdk_sampleTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/PSCBOnlineSample/PSCBOnlineSampleUITests/Info.plist b/PSCBOnlineSample/PSCBOnlineSampleUITests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSampleUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/PSCBOnlineSample/PSCBOnlineSampleUITests/sdk_sampleUITests.swift b/PSCBOnlineSample/PSCBOnlineSampleUITests/sdk_sampleUITests.swift new file mode 100644 index 0000000..0b33773 --- /dev/null +++ b/PSCBOnlineSample/PSCBOnlineSampleUITests/sdk_sampleUITests.swift @@ -0,0 +1,42 @@ +// +// sdk_sampleUITests.swift +// sdk.sampleUITests +// +// Created by OA on 30.10.2020. +// + +import XCTest + +class sdk_sampleUITests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +} diff --git a/PSCBOnlineSample/Podfile.lock b/PSCBOnlineSample/Podfile.lock new file mode 100644 index 0000000..9c20897 --- /dev/null +++ b/PSCBOnlineSample/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - PSCBOnline (1.0.0) + +DEPENDENCIES: + - PSCBOnline (from `https://bitbucket.org/dev_ai/pscbonline.git`, tag `1.0.1`) + +EXTERNAL SOURCES: + PSCBOnline: + :git: https://bitbucket.org/dev_ai/pscbonline.git + :tag: 1.0.1 + +CHECKOUT OPTIONS: + PSCBOnline: + :git: https://bitbucket.org/dev_ai/pscbonline.git + :tag: 1.0.1 + +SPEC CHECKSUMS: + PSCBOnline: 0fe49a5f94b13c88b422774d9225449810f6a437 + +PODFILE CHECKSUM: 56239c9e9e41b37a479ce9620a24a65d5832a2a1 + +COCOAPODS: 1.10.0 diff --git a/PSCBOnlineSample/Pods/Local Podspecs/PSCBOnline.podspec.json b/PSCBOnlineSample/Pods/Local Podspecs/PSCBOnline.podspec.json new file mode 100644 index 0000000..a230daf --- /dev/null +++ b/PSCBOnlineSample/Pods/Local Podspecs/PSCBOnline.podspec.json @@ -0,0 +1,25 @@ +{ + "name": "PSCBOnline", + "version": "1.0.0", + "summary": "An iOS SDK for PSCB Online (OOS) acquiring protocol.", + "description": "An implementation of PSCB-Online (oos.pscb.ru) acquiring protocol for iOS platforms.", + "homepage": "https://oos.pscb.ru/", + "license": { + "type": "PSCB", + "file": "LICENSE.txt" + }, + "authors": { + "Antonov Ilia": "antilya@gmail.com" + }, + "platforms": { + "ios": "10.0" + }, + "source": { + "git": "https://bitbucket.org/dev_ai/oos-ios.git", + "tag": "1.0.0" + }, + "source_files": "PSCBOnline/**/*.{h,m,swift}", + "exclude_files": "", + "swift_versions": "5.3", + "swift_version": "5.3" +} diff --git a/PSCBOnlineSample/Pods/Manifest.lock b/PSCBOnlineSample/Pods/Manifest.lock new file mode 100644 index 0000000..9c20897 --- /dev/null +++ b/PSCBOnlineSample/Pods/Manifest.lock @@ -0,0 +1,22 @@ +PODS: + - PSCBOnline (1.0.0) + +DEPENDENCIES: + - PSCBOnline (from `https://bitbucket.org/dev_ai/pscbonline.git`, tag `1.0.1`) + +EXTERNAL SOURCES: + PSCBOnline: + :git: https://bitbucket.org/dev_ai/pscbonline.git + :tag: 1.0.1 + +CHECKOUT OPTIONS: + PSCBOnline: + :git: https://bitbucket.org/dev_ai/pscbonline.git + :tag: 1.0.1 + +SPEC CHECKSUMS: + PSCBOnline: 0fe49a5f94b13c88b422774d9225449810f6a437 + +PODFILE CHECKSUM: 56239c9e9e41b37a479ce9620a24a65d5832a2a1 + +COCOAPODS: 1.10.0 diff --git a/PSCBOnlineSample/Pods/PSCBOnline/LICENSE.txt b/PSCBOnlineSample/Pods/PSCBOnline/LICENSE.txt new file mode 100644 index 0000000..139d470 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/LICENSE.txt @@ -0,0 +1 @@ +LICENSE BE HERE diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/PSCBOnline.h b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/PSCBOnline.h new file mode 100644 index 0000000..58e4a8b --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/PSCBOnline.h @@ -0,0 +1,18 @@ +// +// PSCBOnline.h +// PSCBOnline +// +// Created by Antonov Ilia on 16.10.2020. +// + +#import + +//! Project version number for PSCBOnline. +FOUNDATION_EXPORT double PSCBOnlineVersionNumber; + +//! Project version string for PSCBOnline. +FOUNDATION_EXPORT const unsigned char PSCBOnlineVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Extension/String.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Extension/String.swift new file mode 100644 index 0000000..b9ff5b9 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Extension/String.swift @@ -0,0 +1,26 @@ +// +// String.swift +// +// +// Created by AntonovIA on 12.10.2020. +// + +import Foundation + +extension String { + + private static let alphanumeric = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + static func random(length: Int, allowedChars: String? = nil) -> String { + let seq: String = ((allowedChars == nil) ? alphanumeric : allowedChars!) as String + var rnd: String = "" + + for _ in 0.. String { + let data = string.data(using: .utf8)! + var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + var sign = "" + + data.withUnsafeBytes { + _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash) + } + + for byte in hash { + sign += String(format: "%02x", UInt8(byte)) + } + + return sign.lowercased() + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/JSONDecoders.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/JSONDecoders.swift new file mode 100644 index 0000000..eb537e2 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/JSONDecoders.swift @@ -0,0 +1,33 @@ +// +// JSONDecoders.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 25.10.2020. +// + +import Foundation + +final public class JSONDecoders { + + public static func iso8601DateAwareDecoder() -> JSONDecoder { + return ISO8601DateAwareJSONDecoder() + } + +} + +// MARK: - ISO8601 date aware JSON Decoder +class ISO8601DateAwareJSONDecoder: JSONDecoder { + + static internal let dateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" + + let dateFormatter: DateFormatter = DateFormatter() + let calendar = Calendar.current + + override init() { + super.init() + + dateFormatter.dateFormat = Self.dateTimeFormat + dateDecodingStrategy = .formatted(dateFormatter) + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/RSAHelper.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/RSAHelper.swift new file mode 100644 index 0000000..9b806f3 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Helpers/RSAHelper.swift @@ -0,0 +1,86 @@ +// +// RSAHelper.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 26.10.2020. +// + +import Foundation + +enum RSAKeyError: Error { + + /// Thrown when provided public key is invalid + case invalidKey + + /// Thrown when encryption of message failed + case encryption(OSStatus) + + /// Thrown when unable to initialize `SecKey` with given key string + case unmanaged(Unmanaged) +} + +public final class RSAHelper { + + internal static let key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPQsWyHaynwoc2tuMbengf1SFase9tPnwtPh4o1tR+94xsWztADdhhUaUBk/68ipaoZE8uSnM9UgdEPmOotFXyUCAwEAAQ==" + + internal static var secKey: SecKey? = nil + + static func initPSCBOnlinePublicKey() throws { + // Treat as assert + guard let keyData = Data(base64Encoded: key) else { + print("Invalid key string: \(key)") + throw RSAKeyError.invalidKey + } + + var attributes: CFDictionary { + return [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeyClass: kSecAttrKeyClassPublic, + kSecAttrKeySizeInBits: 2048, + kSecReturnPersistentRef: true + ] as CFDictionary + } + + var error: Unmanaged? = nil + guard let secKey = SecKeyCreateWithData(keyData as CFData, attributes, &error) else { + print("Error creating a security key with \(String(describing: keyData))") + print(error.debugDescription) + throw RSAKeyError.unmanaged(error!) + } + + Self.secKey = secKey + } + + /// Encrypts given message with OOS public key. + /// + /// - Parameters: + /// - message: A message to encrypt. + /// + /// - Returns: A base64 encoded string + /// + /// - Throws: `RSAKeyError` type error + public static func encryptEncodeBase64(message: String) throws -> String { + // Initialize OOS public key + if Self.secKey == nil { + try Self.initPSCBOnlinePublicKey() + } + + // Initialize buffers + let sKey = Self.secKey! + let buff = [UInt8](message.utf8) + + // Mutable encryption refs + var size = SecKeyGetBlockSize(sKey) + var kBuf = [UInt8](repeating: 0, count: size) + + let status = SecKeyEncrypt(sKey, SecPadding.PKCS1, buff, buff.count, &kBuf, &size) + + // Sanity check + guard status == errSecSuccess else { + throw RSAKeyError.encryption(status) + } + + return Data(bytes: kBuf, count: size).base64EncodedString() + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CardData.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CardData.swift new file mode 100644 index 0000000..bd8ed9a --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CardData.swift @@ -0,0 +1,92 @@ +// +// CardData.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 21.10.2020. +// + +import Foundation +import PassKit + +public enum CardDataError: Error { + case invalidExiryDate(String) + case invalidCvCode + case invalidPan +} + +/// Billing info. +/// Detailed card information +public struct CardData { + let pan: String + let expiryYear: Int + let expiryMonth: Int + let cardholder: String? + let cvCode: String + + /// Constructs card data from all necessary for billing fields + /// + /// - Parameters: + /// - pan: Card number + /// - expiryYear: A full year number (e.g: `2020`). For production cannot be in the past + /// - expiryMonth: A month number from 1 to 12. + /// - cvCode: CVC/CVV number + /// - cardholder: (Optional) Cardholder name in latin. + /// + /// - Returns: optional instance of a new card. If validation fails returns nil + public init?(pan: String, expiryYear: Int, expiryMonth: Int, cvCode: String, cardholder: String? = nil) { + guard expiryMonth >= 1 && expiryMonth <= 12 else { + print("Month can be between 1 and 12") + return nil + } + + #if !DEBUG + // todo check year + month in the past + let currentYear = Calendar.current.component(.year, from: Date()) + guard expiryYear >= currentYear else { + print("Year must be current or in the future") + return nil + } + #endif + + self.pan = pan + self.expiryMonth = expiryMonth + self.expiryYear = expiryYear + self.cvCode = cvCode + self.cardholder = cardholder + } + + /// - Returns: A last 2 digits of the expiry year + public func getExpYearString() -> String { + return String(String(expiryYear).dropFirst(2)) + } + + /// - Returns: A zero padded expiry month string + public func getExpMonthString() -> String { + return expiryMonth < 10 ? "0\(self.expiryMonth)" : String(self.expiryMonth) + } + +} + +extension CardData { + + internal static let pubKey: Data = { + let key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPQsWyHaynwoc2tuMbengf1SFase9tPnwtPh4o1tR+94xsWztADdhhUaUBk/68ipaoZE8uSnM9UgdEPmOotFXyUCAwEAAQ==" + + return Data(base64Encoded: key)! + }() + + + /// Produces a cryptogram string from given `CardData` + /// See: https://docs.pscb.ru/oos/shpa.html#shlyuz-prozrachnoj-avtorizacii-sozdanie-platezha-otvet + /// + /// - Returns: a Base64 encoded cryptogram string + public func toCryptgramString() throws -> String { + let month = self.getExpMonthString() + let year = self.getExpYearString() + let joinedString = "\(self.pan)|\(month)|\(year)|\(cvCode)\(self.cardholder ?? "")" + let base64Encode = try RSAHelper.encryptEncodeBase64(message: joinedString) + + return base64Encode + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CustomerData.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CustomerData.swift new file mode 100644 index 0000000..710ea0b --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/CustomerData.swift @@ -0,0 +1,29 @@ +// +// CustomerData.swift +// +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation + +/// A costumer data to present in PaymentData +public struct CustomerData: Codable { + + /// Unique costumer ID + let account: String + + let comment: String? + + let email: String? + + let phone: String? + + enum CodingKeys: String, CodingKey { + case account = "customerAccount" + case comment = "customerComment" + case email = "customerEmail" + case phone = "customerPhone" + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Payment.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Payment.swift new file mode 100644 index 0000000..74b0b37 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Payment.swift @@ -0,0 +1,90 @@ +// +// Payment.swift +// +// +// Created by AntonovIA on 12.10.2020. +// + +import Foundation + +// MARK: - Payment methods + +internal enum PaymentMethods: String { + case shpa = "ac-shpa" +} + +// MARK: - Request Message + +public struct Payment: Encodable { + + // Required: + + /// Payment amount in rub + /// min: 1.00 + public let amount: Decimal + + /// Your market order ID + /// maxlength: 20 + public let orderId: String + + // Payment method + internal let paymentMethod: PaymentMethods = .shpa + + // Optional: + + /// Human readable `orderId` + /// Defaults to `orderId` + var showOrderId: String? + + /// Detailed text describing this order payment. + var details: String? + + /// Data about paying customer + var customer: CustomerData? + + // + var recurrentable: Bool = false + + public init(amount: Decimal, orderId: String, + showOrderId: String? = nil, details: String? = nil, + customer: CustomerData? = nil, recurrentable: Bool = false) { + self.amount = amount + self.orderId = orderId + self.showOrderId = (showOrderId == nil) ? orderId : showOrderId + self.details = details + self.customer = customer + self.recurrentable = recurrentable + } + + // MARK: - Encoder + + private enum CodingKeys: String, CodingKey { + case amount, orderId, showOrderId, details, recurrentable, customer + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(amount, forKey: .amount) + try container.encode(orderId, forKey: .orderId) + try container.encode(showOrderId, forKey: .showOrderId) + try container.encode(details, forKey: .details) + try container.encode(recurrentable, forKey: .recurrentable) + + // Customer + try customer?.encode(to: encoder) + } + + #if DEBUG + + public static let example = Payment( + amount: 150.00, orderId: String.random(length: 6), + details: "Wonderful warm socks", + customer: CustomerData( + account: "ID-12345", comment: "By tomorrow please", + email: "foo@bar.com", phone: "+7 900 000 00 00" + ) + ) + + #endif + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/RequestWrapper.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/RequestWrapper.swift new file mode 100644 index 0000000..ad4aebc --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/RequestWrapper.swift @@ -0,0 +1,44 @@ +// +// RequestWrapper.swift +// +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation + +// MARK: - Top level request + +/// Top level request wrapper for OOS requests +public struct RequestWrapper: Encodable { + + /// Merchant ID + public let marketPlaceId: String + + /// Payment info + public let payment: Payment + + /// Encoded card data + public let cardData: String + + /// Creates instance of RequestWrapper + /// + /// - Parameters: + /// - marketPlaceId: Your OOS market place ID + /// - payment: Payment details object + /// - cardData: Encoded card data + /// + /// - Returns: Prepared request ready to fire + public init(marketPlaceId: String, payment: Payment, cardData: String) { + self.marketPlaceId = marketPlaceId + self.payment = payment + self.cardData = cardData + } + + private enum CodingKeys: String, CodingKey { + case marketPlaceId = "marketPlace" + case payment + case cardData + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Response.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Response.swift new file mode 100644 index 0000000..d23f383 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Models/Response.swift @@ -0,0 +1,100 @@ +// +// Response.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 23.10.2020. +// + +import Foundation + +// MARK: - PSCB OOS Response status +public enum ResponseStatus: String, Decodable { + case success = "STATUS_SUCCESS" + case failure = "STATUS_FAILURE" +} + +// MARK: - Acquiring data +public struct AcquiringResponseData: Decodable { + public let paReq: String? + public let order: String? + public let termUrl: String? + public let url: String? + public let md: String? + + private enum CodingKeys: String, CodingKey { + case order, termUrl = "TermUrl", url = "URL", md = "MD", paReq = "PaReq" + } +} + +// MARK: - OOS Error + +/// An error structure for OOS errors returned in flat JSON +/// `errorCode` and `errorDescription` +public struct ResponseError: Decodable { + + public let code: String + public let description: String? + + private enum CodingKeys: String, CodingKey { + case code = "errorCode" + case description = "errorDescription" + } + +} + +// MARK: - OOS Response + +/// JSON Response from OOS API +public struct Response: Decodable { + + public let status: ResponseStatus + public let requestId: String + public let error: ResponseError? + public let payment: ResponsePayment? + public let acquiringData: AcquiringResponseData? + public let description: String? + + private enum CodingKeys: String, CodingKey { + case status, requestId, payment, acquiringData, description + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.status = try container.decode(ResponseStatus.self, forKey: .status) + self.requestId = try container.decode(String.self, forKey: .requestId) + self.description = try? container.decode(String.self, forKey: .description) + + // Decode flat and nested data into nested structs + self.payment = try? container.decode(ResponsePayment.self, forKey: .payment) + self.acquiringData = try? AcquiringResponseData(from: decoder) + self.error = try? ResponseError(from: decoder) + } + +} + +// MARK: - Payment status +/// Payment stats +/// see: https://docs.pscb.ru/oos/index.html#obshaya-informaciya-spravochniki-statusy-platezhej +public enum PaymentState: String, Decodable { + case sent = "sent" + case new = "new" + case end = "end" + case refunded = "ref" + case hold = "hold" + case expired = "exp" + case canceled = "canceled" + case error = "error" + case rejected = "rej" + case undefined = "undef" +} + +// MARK: - Payment response struct +public struct ResponsePayment: Decodable { + public let orderId: String + public let showOrderId: String + public let paymentId: String + public let amount: Decimal + public let state: PaymentState + public let marketPlace: UInt16 + public let stateDate: Date +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBAPI.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBAPI.swift new file mode 100644 index 0000000..83e04d6 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBAPI.swift @@ -0,0 +1,55 @@ +// +// OOSAPI.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 27.10.2020. +// + +import Foundation +import PassKit + +/// Utility fabric methods required for PSCB API. +public class PSCBAPI { + + public static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard] + + /// - Returns: a tuple describing if application `canMakePayments` and `canSetupCards` using supported networks. + public class func canMakePayments() -> (canMakePayments: Bool, canSetupCards: Bool) { + return ( + PKPaymentAuthorizationController.canMakePayments(), + PKPaymentAuthorizationController.canMakePayments(usingNetworks: supportedNetworks) + ) + } + + /// Creates a default instance of `PKPaymentRequest` with pre-default parameters. + /// + /// - Returns: `PKPaymentRequest` + public class func makePaymentRequest(items: [PKPaymentSummaryItem]) -> PKPaymentRequest { + return makePaymentRequest(merchantId: "merchant.pscb.pay", items: items) + } + + /// Creates a default instance of `PKPaymentRequest` with pre-default parameters. + /// + /// - Parameters: + /// - merchantId: Your Apple Pay merchant ID + /// - items: Summary items + /// + /// - Returns: `PKPaymentRequest` + public class func makePaymentRequest(merchantId: String, items: [PKPaymentSummaryItem]) -> PKPaymentRequest { + let request = PKPaymentRequest() + request.merchantIdentifier = merchantId + request.supportedNetworks = Self.supportedNetworks + + if #available(iOS 11.0, *) { + //request.supportedCountries = ["RU", "UA", "BY", "US"] + } + + request.merchantCapabilities = .capability3DS + request.countryCode = "RU" + request.currencyCode = "RUB" + request.paymentSummaryItems = items + + return request + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBOnlineClient.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBOnlineClient.swift new file mode 100644 index 0000000..95538fb --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PSCBOnlineClient.swift @@ -0,0 +1,306 @@ +// +// OOSAPIClient.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 12.10.2020. +// + +import Foundation +import PassKit + +// MARK: - Environments + +public enum BackendEnvironment: String { + + case production = "oos.pscb.ru" + case sandbox = "oosdemo.pscb.ru" + +} + +// MARK: - Request status + +/// Backend request status +/// Consists of two possible states: `.success` and `.failure`. +/// +/// This one represents if request to the backend server was successful +public enum RequestStatus { + case success, failure +} + +// MARK: - Response wrapper + +/// Backend response +public struct BackendResponse { + + /// Represents request status + public let status: RequestStatus + + /// Hold error information if request is a `.failure` + public let error: Error? + + /// Holds response information if request is a `.success` + public let response: Response? +} + +// MARK: - Alias for completion handler + +/// Callback for `OOSAPIClient.send` method +public typealias APICompletionHandler = (BackendResponse) -> Void + +/// Callback for another `OOSAPIClient.send` method which fires after certain guards ensure success or failure +/// to simplify API usage +public typealias PostResponseHandler = (Error?, Response?) -> Void + +// MARK: - API Integration errors + +/// Possible erros when dealing with OOS backend +public enum OOSErrors: Error { + case noData + case parse(Error) + case cause(Error) + + /// Consists of error code and error description + case backend(String, String) +} + +// MARK: - API Client + +/// Implementation of OOS Merchant API HTTP protocol. +final public class PSCBOnlineClient { + + private lazy var urlSession: URLSession = { + URLSession(configuration: .default, delegate: nil, delegateQueue: .main) + }() + + private lazy var url: URL = { + var components = URLComponents() + components.scheme = "https" + components.host = self.environment.rawValue + components.path = "/merchantApi/payShpa" + + return components.url! + }() + + private let decoder = JSONDecoders.iso8601DateAwareDecoder() + + // init: + + let environment: BackendEnvironment + let marketPlaceId: String + let signingKey: String + + /// Initializes `OOSAPIClient` + /// + /// - Parameters: + /// - environment: Backend environment. Which one to use. For testing environment use `.sandbox` + /// - marketPlaceId: Your OOS market-place ID + /// - siginingKey: Your OOS signing key + public init(environment: BackendEnvironment, marketPlaceId: String, signingKey: String) { + self.environment = environment + self.marketPlaceId = marketPlaceId + self.signingKey = signingKey + } + + // impl: + + /// Creates instance of `RequestWrapper` for a backend to process from given PKPayment instance and other details + /// + /// - Parameters: + /// - payment: authorized PKPayment instance + /// - amount: total order amount + /// - orderId: Unique merchant order ID + /// + /// - Returns: RequestWrapper instance for backend + public func makeRequestWithPayment(payment: PKPayment, amount: Decimal, orderId: String) throws -> RequestWrapper { + return try makeRequestWithPayment(pkPayment: payment, payment: Payment(amount: amount, orderId: orderId)) + } + + /// Creates instance of `RequestWrapper` for a backend to process from given `PKPayment` instance and backend `Payment` instance + /// + /// - Parameters: + /// - pkPayment: authorized `PKPayment` instance + /// - payment: backend `Payment` details + /// + /// - Returns: RequestWrapper instance for backend + public func makeRequestWithPayment(pkPayment: PKPayment, payment: Payment) throws -> RequestWrapper { + // Get card data cryptogram from payment token + let cardDataCrypto = try pkPayment.token.toCryptogramString() + + // Backend request wrapper + let requestWrapper = RequestWrapper( + marketPlaceId: self.marketPlaceId, + payment: payment, + cardData: cardDataCrypto + ) + + // Fail early + try requestWrapper.assumeSerializes() + + return requestWrapper + } + + /// Creates instance of `RequestWrapper` for a backend to process from raw card data instead of ApplePay token + /// + /// Example: + /// ``` + /// let card = CardData( + /// pan: "409444400001234", + /// expiryYear: 2025, + /// expiryMonth: 12, + /// cvCode: "000", + /// cardholder: "JOHN DOE" + /// ) + /// + /// let payment = Payment(amount: Decimal(1500), orderId: "XC-12345") + /// let request = try apiClient.createRequestWithCardData(card: card, payment: payment) + /// + /// // Send to backend: + /// apiClient.send(request) { (response) in /code/ } + /// ``` + /// + /// - Parameters: + /// - cardData: an instance of card data. + public func makeRequestWithCardData(card: CardData, payment: Payment) throws -> RequestWrapper { + let cryptogram = try card.toCryptgramString() + let request = RequestWrapper( + marketPlaceId: self.marketPlaceId, + payment: payment, + cardData: cryptogram + ) + + // Fail-early compile + try request.assumeSerializes() + + return request + } + + /// Signs and sends compiled `RequestWrapper` to the backend server + /// Fires `APICompletionHandler` once requests succeeds or fails + /// + /// - Parameters: + /// - request: `RequestWrapper` created from `createRequestWithPayment(...)` + /// - completionHander: `APICompletionHandler` a callback for when requests succeeds or fails + /// + public func send(_ request: RequestWrapper, completionHandler: @escaping APICompletionHandler) { + // Calculate signature and get HTTP body at the same time + let httpBody = try! request.serializeToString() + let signature = calculateSignature(httpBody) + + // Request params + let url = self.url + var req = URLRequest(url: url) + + // Set request parameters + req.httpMethod = "POST" + req.httpBody = httpBody.data(using: .utf8) + req.setValue(signature, forHTTPHeaderField: "Signature") + + print(">> Request JSON: \(String(describing: String(data: req.httpBody!, encoding: .utf8)))") + + let task = urlSession.dataTask(with: req) { (data, res, err) in + guard err == nil else { + let error = self.err_requestError(req, error: err) + completionHandler(error) + return + } + + guard let data = data else { + let error = self.failure(req, error: OOSErrors.noData) + completionHandler(error) + return + } + + print("<< Response data: \(String(data: data, encoding: .utf8) ?? "N/A")") + + do { + let response = try self.decoder.decode(Response.self, from: data) + + // Finaly success + let success = BackendResponse(status: .success, error: nil, response: response) + + completionHandler(success) + } catch let error { + print("Failed to do task on request \(req)") + print(error.localizedDescription) + + // Reading and parsing errors + let failure = self.failure(req, error: .parse(error)) + completionHandler(failure) + } + + } + + // Fire task + task.resume() + } + + /// Signs and sends compiled `RequestWrapper` to the backend server + /// Fires `PostResponseHandler` once requests succeeds or fails. + /// `PostResponseHandler` accepts two arguments: `Error?` and `Response?`. + /// + /// If requests succeeds and payment in desired state `Error?` will always be `nil`. + /// `Response?` presents on some errors and on all successes. + /// + /// This is an utility method to reduce boilerplate for necessary checks. + /// + /// - Parameters: + /// - request: `RequestWrapper` created from `createRequestWithPayment(...)` + /// - completionHander: `APICompletionHandler` a callback for when requests succeeds or fails + /// + public func send(_ request: RequestWrapper, responseHandler: @escaping PostResponseHandler) { + // Construct a closure wrapper with predefined guards and checks + let wrapper: APICompletionHandler = { (backendResponse) in + // HTTP request succeeded? + guard backendResponse.status == .success else { + print("Failed to execute request due to error: \(String(describing: backendResponse.error))") + + responseHandler(OOSErrors.cause(backendResponse.error!), nil) + return + } + + // Backend returned valid response? + guard let response = backendResponse.response else { + print("Backend returned empty body") + + responseHandler(OOSErrors.noData, nil) + return + } + + // Backend payment succeeded? + guard response.status == .success else { + print("Unable to process payment") + + let responseError = response.error + let backendError = OOSErrors.backend(responseError?.code ?? "FAILED", responseError?.description ?? "") + + // At this point we can pass response too + responseHandler(backendError, response) + return + } + + // Finally succeeds + responseHandler(nil, response) + } + + // Send using more lower-level method above + send(request, completionHandler: wrapper) + } + + // MARK: - Private + + private func err_requestError(_ req: URLRequest, error: Error?) -> BackendResponse { + print("Failed to do task on request \(req) with error: \(String(describing: error))") + return BackendResponse(status: .failure, error: OOSErrors.cause(error!), response: nil) + } + + private func failure(_ req: URLRequest, error: OOSErrors) -> BackendResponse { + print("Request \(req) failed with error: \(String(describing: error))") + return BackendResponse(status: .failure, error: error, response: nil) + } + + private func calculateSignature(_ jsonString: String) -> String { + let composite = (jsonString + self.signingKey) + return DigestHelper.sha256String(composite) + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PaymentHandler.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PaymentHandler.swift new file mode 100644 index 0000000..a6bad97 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/PaymentHandler.swift @@ -0,0 +1,113 @@ +// +// PaymentHandler.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 16.10.2020. +// + +import Foundation +import PassKit + +public typealias PaymentCompletionHandler = (Bool) -> Void + +public class ApplePayHandler: NSObject { + + static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard] + + // MARK: - Fields + + public let merchantId: String + public let merchantKey: String + public let summaryItems: [PKPaymentSummaryItem] + + // MARK: - Properties + + var paymentController: PKPaymentAuthorizationController? + var paymentStatus: PKPaymentAuthorizationStatus = .failure + var completionHandler: PaymentCompletionHandler? + var payment: Payment? + + public init?(merchantId: String, merchantKey: String, summaryItems: [PKPaymentSummaryItem]) { + guard PKPaymentAuthorizationController.canMakePayments(usingNetworks: Self.supportedNetworks) else { + print("Could not instantiate ApplePayHandler. Cannot make payments with provided networks") + return nil + } + + self.merchantId = merchantId + self.merchantKey = merchantKey + self.summaryItems = summaryItems + } + + public func handle(payment: Payment, completion: @escaping PaymentCompletionHandler) { + self.completionHandler = completion + self.payment = payment + + NSLog("About to handle payment: \(payment)") + + paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest) + paymentController?.delegate = self + paymentController?.present { (presented) in + if !presented { + NSLog("Could not present PKPaymentAuthorizationController") + self.completionHandler!(false) + } else { + NSLog("PKPaymentAuthorizationController presented") + } + } + + } + + // MARK: - Private details + + private var paymentRequest: PKPaymentRequest { + let request = PKPaymentRequest() + + request.countryCode = "RU" + request.merchantIdentifier = "merchant.pscb.pay" + request.currencyCode = "RUB" + request.supportedNetworks = Self.supportedNetworks + request.merchantCapabilities = .capability3DS + request.paymentSummaryItems = summaryItems + + return request + } + +} + + +// MARK: - Extension for PKPaymentAuthorizationControllerDelegate + +extension ApplePayHandler: PKPaymentAuthorizationControllerDelegate { + + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, + didAuthorizePayment payment: PKPayment, + completion: @escaping (PKPaymentAuthorizationStatus) -> Void) { + +// print("Payment string") +// let paymentString = try! payment.serializeToString() +// print(paymentString) +// +// // +// +// self.paymentStatus = .success + completion(PKPaymentAuthorizationStatus.success) + } + + @available(iOS 11.0, *) + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { +// +// NSLog("About to send request to backend") +// let paymentString = try! payment.serializeToString() +// +// NSLog("Payment JSON: \(paymentString)") +// + let result = PKPaymentAuthorizationResult(status: .success, errors: nil) + completion(result) + self.completionHandler?(true) + } + + public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { + controller.dismiss(completion: nil) + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift new file mode 100644 index 0000000..a64bacd --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift @@ -0,0 +1,79 @@ +// +// PKPaymentToken+Serializable.swift +// PSCB-OOS-iOS +// +// Created by OA on 17.10.2020. +// + +import Foundation +import PassKit + +// MARK: - Comfront to serializable +extension PKPaymentToken: Serializable { + + // Serializes token to a JSONLike dictionary + public func serializeToJSON() -> JSONDict { + let paymentJson: JSONDict? = try? JSONSerialization.jsonObject( + with: self.paymentData, options: .mutableContainers + ) as? JSONDict + + var paymentType: String = "debit" + var methodAndNetwork: JSONDict = [ + "network": "", + "type": paymentType, + "displayName": "" + ] + + if #available(iOS 9.0, *) { + methodAndNetwork = [ + "network": self.paymentMethod.network?.rawValue ?? "", + "type": paymentType, + "displayName": self.paymentMethod.displayName ?? "" + ] + + switch self.paymentMethod.type { + case .debit: + paymentType = "debit" + case .credit: + paymentType = "credit" + case .store: + paymentType = "store" + case .prepaid: + paymentType = "prepaid" + default: + paymentType = "unknown" + } + } + + return [ + "paymentData": paymentJson, + "transactionIdentifier": self.transactionIdentifier, + "paymentMethod": methodAndNetwork + ] as JSONDict + } + +} + +// MARK: - To string cryptogram +extension PKPaymentToken { + + private func paymentJSONData() -> JSONDict? { + let json = self.serializeToJSON() + let data = json["paymentData"] as! JSONDict? + + return data + } + + /// Creates a Base64 encoded cryptogram string accepted by PSCB OOS protocol + /// May throw JSON serialization errors if token could not be converted to JSON string before writing a cryptogram. + /// + /// - Returns: Base64 encoded string + public func toCryptogramString() throws -> String { + let json = self.paymentJSONData() + let data = try JSONSerialization.data(withJSONObject: json!, options: []) + // let string = String(data: data, encoding: .utf8)! + + return data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)) + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Payment+Serializable.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Payment+Serializable.swift new file mode 100644 index 0000000..74767bd --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Payment+Serializable.swift @@ -0,0 +1,27 @@ +// +// Payment+Serializable.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 21.10.2020. +// + +import Foundation + +extension Payment: Serializable { + + public func serializeToJSON() -> JSONDict { + var json = JSONDict() + json["orderId"] = self.orderId + json["amount"] = self.amount + json["showOrderId"] = self.showOrderId + json["details"] = self.details + json["recurrentable"] = self.recurrentable + json["customerAccount"] = self.customer?.account + json["customerComment"] = self.customer?.comment + json["customerEmail"] = self.customer?.email + json["customerPhone"] = self.customer?.phone + + return json + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift new file mode 100644 index 0000000..25a1bdf --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift @@ -0,0 +1,21 @@ +// +// RequestWrapper+Serializable.swift +// PSCB-OOS-iOS +// +// Created by Antonov Ilia on 18.10.2020. +// + +import Foundation + +extension RequestWrapper: Serializable { + + public func serializeToJSON() -> JSONDict { + var json = JSONDict() + json["marketPlace"] = self.marketPlaceId + json["payment"] = self.payment.serializeToJSON() + json["cardData"] = self.cardData + + return json + } + +} diff --git a/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Serializable.swift b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Serializable.swift new file mode 100644 index 0000000..520de98 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/PSCBOnline/Sources/Serializable/Serializable.swift @@ -0,0 +1,61 @@ +// +// Serializable.swift +// PSCB-OOS-iOS +// +// Created by OA on 16.10.2020. +// + +import Foundation + +// MARK: - Serializable + +public protocol Serializable { + + /// Serializes current object to generic JSON-Like dictionary + func serializeToJSON() -> JSONDict + +} + +// MARK: - Extension + +public extension Serializable { + + /// Serializes current object to data + func serializeToData() throws -> Data { +// let encoder = JSONEncoder() +// let data = try encoder.encode(self.serializeToJSON()) +// +// return data + return try JSONSerialization.data( + withJSONObject: self.serializeToJSON(), + options: [] + ) + } + + /// Serialzes to JSON-String + func serializeToString() throws -> String { + let data = try self.serializeToData() + return String(data: data, encoding: .utf8)! + } + + /// Used for checking purposes if this object can be serialized without exception + func assumeSerializes() throws { + try serializeToString() + } + +} + +// MARK: - JSONDict + +public typealias JSONDict = [AnyHashable: AnyHashable] + +//extension JSONDict { +// +// public mutating func add(key: T, nullable value: JSONDict.Value?) where T.RawValue == JSONDict.Key { +// if let value = value { +// self.updateValue(value, forKey: key.rawValue) +// } +// } +// +//} + diff --git a/PSCBOnlineSample/Pods/PSCBOnline/README.md b/PSCBOnlineSample/Pods/PSCBOnline/README.md new file mode 100644 index 0000000..c215649 --- /dev/null +++ b/PSCBOnlineSample/Pods/PSCBOnline/README.md @@ -0,0 +1,217 @@ +# ПСКБ Платежи iOS SDK + +[![Platform](https://img.shields.io/badge/Support-iOS%2010.0+-brightgreen.svg)](https://img.shields.io/badge/Support-iOS%2010.3+-brightgreen.svg) + +Библиотека является дополнением к API системы интернет-эквайринга [ПСКБ "Платежи"](https://online.pscb.ru) +и позволяет подключить приём платежей по картам в мобильных приложениях iOS с минимальными усилиями. + +## Возможности + +На текущий момент библиотека поддерживает: + + - Apple Pay + - Оплата картами + +## Подключение зависимостей + +1. Установите CocoaPods 1.10.0 или выше + +```zsh +gem install cocoapods +``` +[Официальная документация по установке CocoaPods](https://guides.cocoapods.org/using/getting-started.html) + +2.  Создайте в своём приложении `Podfile` + +Это также можно сделать при помощи команды `pod init` , находясь в директории своего проекта. (В таком случае будет создан `Podfile` с настройками по умолчанию) + +3. Добавьте зависимости в `Podfile` + +```ruby +platform :ios, '10.0' + +target '' do + use_frameworks! + + pod 'PSCBOnline', :git => "https://bitbucket.org/dev_ai/pscbonline.git", :tag => "1.0.0" + +end +``` + +> `` - Название проекта вашего приложения в XCode + +4. Выполните команду `pod install` + +## Интеграция + +1. Для работы с библиотекой импортируйте зависимости в нужный файл проекта: + +```swift +import PSCBOnline +``` + +2. Создайте экземпляр `PSCBOnlineClient` с вашими настройками: + +```swift +let apiClient = PSCBOnlineClient( + environment: .sandbox, + marketPlaceId: "", + signingKey: "" +) +``` + +> `environment` -  окружение, в рамках которого библиотека взаимодействует с сервисом. `.sandbox` - тестовое окружение; `.production` - продуктовое. +> `Your MarketPlace ID` - ваш идентификатор в системе ПСКБ-Онлайн. +> `Your Signing Key` - ваш ключ подписи запросов к системе. + +3. Создайте экземпляр `Payment` + +```swift +let payment = Payment(amount: Decimal(1000.00), orderId: "Order-ID") +``` +> `amount` - сумма в рублях. (_На текущий момент другая валюта не поддерживается._) +> `orderId` - уникальный идентификатор заказа в рамках магазина. + +_Для детальной информации, какие параметры принимает смотрите документацию `Payment`._ + +---- + +Дальнейшая интеграция отличается от способа оплаты. + +## Доступные способы оплаты + +Сейчас в SDK доступна оплата: + + - Банковкой кратой + - Apple Pay + + Для их настройки реализации смотрите дальше. + +### Приём оплаты банковскимикартами + +1. Для приёма оплаты картами нужно создать экземпляр класса `CardData`. + +```swift +let card = CardData( + pan: "4761349750010326", + expiryYear: 2022, + expiryMonth: 12, + cvCode: "851" +) +``` + +2. Создать токен запроса, используя экземпляр `PSCBOnlineClient`, созданный ранее. + +```swift +let request = try! client.makeRequestWithCardData(card: card, payment: payment) +``` + +3. Отправить токен запроса на сервер ПСКБ-Онлайн. + +```swift +// Send request to backend +client.send(request, responseHandler: { (error, response) in + guard nil == error && nil != response else { + print("Error sending request: \(String(describing: error))") + return + } + + print("Successful request:") + print(response!) +}) +``` + +> В случае успешного выполнения запроса, `response` будет содержать информацию о принятом платеже, его ID, состояние и прочие данные. + +### Приём оплаты Apple Pay + +Для приёма платежей через Apple Pay вы должны зарегестрировать Merchant ID в Apple. + +Помимо `merchant ID` необходимо настроить сертификат обработки запросов (`Payment Processing Certificate`) и передать его ПСКБ-Онлайн. Этим сертификатом Apple будет шифровать данные банковских карт перед отправкой на сервер ПСКБ-Онлайн. + +Все пререквизиты описаны на сайте [официальной документации Apple](https://developer.apple.com/documentation/passkit/apple_pay/setting_up_apple_pay_requirements). + +Также вы можете ознакомиться сподробной инструкцией на сайте документации [ПСКБ Онлайн](https://docs.pscb.ru/oos/advanced.html#dopolnitelnye-opcii-apple-pay). + +--- + +После выполнения пререквизитов, в коде необходимо: + +1. Импортировать `PassKit`: + +```swift +import PassKit +``` + +2. Создать экземпляр класса `PKPaymentAuthorizationController` и настроить делегирующий класс `PKPaymentAuthorizationControllerDelegate`: + +Пример: + +```swift +import PassKit +import PSCBOnline + +class ApplePayHandler: NSObject { + + public func handleApplePay(payment: Payment) { + // Позиции оплаты для представления пользователя + let items = [PKPaymentSummaryItem(label: "Shoes", amount: NSDecimalNumber(intergerLiteral: 1000))] + + // Запрос на оплату для PKPaymentAuthorizationController + let paymentRequest = PSCBAPI.makePaymentRequest(merchantId: "", items: []) + + // Вызов модуля оплаты + let authorizationController = PKPaymentAuthorizationController(paymentRequest: paymentRequest) + + authorizationController?.delegate = self + authorizationController?.present(completion: { presented in + if presented { + print("Controller presented") + } else { + print("Controller could not be presented") + } + }) + } +} + +extension ApplePayHandler: PKPaymentAuthorizationControllerDelegate { + + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, + didAuthorizePayment payment: PKPayment, + handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { + + // 1. + // Вызывается после авторизации платежа плательщиком биометрическими данными или паролем + } + + public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { + // 2. + // Вызывается после того, как платёж совершён или пользователь закрыл модуль оплаты. + } + +} +``` + +> `` - Ваш идентификатор мерчанта. + +3. Далее в примере выше в п.1 и п.2 реализовать необходимую логику отправки запроса на сервер ПСКБ-Онлайн. + Для пункта 1 - это создание токена запроса (используя `client.makeRequestWithPayment(pkPayment, pscbPayment)` и отправка его на сервер: + +```swift +// Request token +let request = try! client.makeRequestWithPayment(pkPayment: pkPayment, pscbPayment: payment) + +// Sending request to backend +client.send(request, responseHandler: { (error, response) in + if (error == nil && response != nil) { + completion(PKPaymentAuthorizationResult(status: .success, errors: nil)) + } else { + print("Error sending payment: \(String(describing: error))") + completion(PKPaymentAuthorizationResult(status: .failure, errors: nil)) + } +}) +``` + +4. А для пункта 2 - обработка закрытия модуля оплаты. + +## Описание классов и параметров diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/project.pbxproj b/PSCBOnlineSample/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..521e484 --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1030 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 08153B37829081830118DC3FDA1C8891 /* RequestWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D302DD80F732D394A15C10B518CA9793 /* RequestWrapper.swift */; }; + 13C0ACA010CFDF4876F85B5308F50E1B /* Pods-PSCBOnlineSample-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 07A5FA728F8AB4366597F4A40E03957E /* Pods-PSCBOnlineSample-dummy.m */; }; + 1639B897ACE3EDFA100BC2BA2CDB90F8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; + 1D41A2AE55314D31499ECB25848838D4 /* PSCBOnlineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E203FA4820121CCEA995CEE6472ADCC6 /* PSCBOnlineClient.swift */; }; + 22C319C0A78167ACBCC7E91EE27598C4 /* PKPaymentToken+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002D20147E567CDBEB2824598F4716CB /* PKPaymentToken+Serializable.swift */; }; + 232BCBC67C898EC14B4DE9B1B75991B0 /* CardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5183B110BD9174B18FFF38079FEB02 /* CardData.swift */; }; + 238AC86B87F44EB8205349B411A8003C /* Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CDD28AD2DDBACF450F4152A9284250 /* Serializable.swift */; }; + 269AAEA2EB76940DD8E64F0855F4CFFE /* JSONDecoders.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE139BB75A732730123A0FF4C0CB9DDB /* JSONDecoders.swift */; }; + 283419E95C403C3E04992A6FA48BB861 /* Payment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2E4E6B8D912C02E7B4AB7E039583EE /* Payment.swift */; }; + 4C712069DB64560C09EB60BC1CF859A0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; + 4E44BDDA6DD7F1183146048FD6C95764 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F4E90E25A6D567DEEEBFD1C4F45D15D /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m */; }; + 4E473622002751DBAC7B0C7E9659939A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; + 5F5D4DFE18ED0AAD59C04E47975E20F7 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A9AC4D172CDD3DDC2E65569FCA727D3A /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5F5F26822516C9474E7AD01114879F78 /* CustomerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 270D42B4EB19C66D7A39FF5F2E0C2B43 /* CustomerData.swift */; }; + 62268E998A000DAADD5E9BA5D0F2EE6F /* PaymentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA42370209FF35773B6B0C7281AF1795 /* PaymentHandler.swift */; }; + 71803D0B8BC9EC5BA1199DC05D6554D4 /* PSCBOnline.h in Headers */ = {isa = PBXBuildFile; fileRef = E7C8744A223F4FAA81D82BFA5F315A8B /* PSCBOnline.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 725B068C5E0B4AD9FF917A56C6C53049 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B60541BCD4B1ADE8420D889E1D5CBBC /* String.swift */; }; + 873C6813FE5DB5C3913FFD8FFFEBCAD9 /* PSCBOnline-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B63E76D69519F459D9BB11D8F07272 /* PSCBOnline-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 95FFF40AE0BB33405D8CC97AB08E4A38 /* Pods-PSCBOnlineSampleTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5C736A601CF7F3441804459B3AAF43 /* Pods-PSCBOnlineSampleTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B0C19FDF374038C5043A35C7DBE8946B /* RSAHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F44ECCC00616D9D42F57713A86E39D0 /* RSAHelper.swift */; }; + BC27C4D84BBCE78CA390FAC2DBD57B26 /* Payment+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9531D3ED1E4E9C21F2AE0C026D64EC /* Payment+Serializable.swift */; }; + D18BBEC284892F81901DFD0BD22B07DC /* DigestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55A13187A86E701DCD971C0A528A814C /* DigestHelper.swift */; }; + D319206921562386DADE2F3A04553414 /* RequestWrapper+Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF470A0A6171E66AF57ACC8C5BDE637B /* RequestWrapper+Serializable.swift */; }; + D80F58C566E10DF3FAA7AFAAF3BCFD7B /* PSCBAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 766D7A8DB0E03B619C43BBB03FE105E2 /* PSCBAPI.swift */; }; + DAA505D95F5A8AB9E1A058A0AAB37D62 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6DD36A515037D0DF509ED0DAD6DCABA /* Response.swift */; }; + DF10B5E93A702195E92624CA2ED6240C /* Pods-PSCBOnlineSampleTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E8C86CC7D69E4B87AC8AF542842047F /* Pods-PSCBOnlineSampleTests-dummy.m */; }; + E481B26E484F433D679AE3C26A849E50 /* Pods-PSCBOnlineSample-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E7C2E55F1D481F4F7D9CCBF9B5CF1F5 /* Pods-PSCBOnlineSample-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E63D1F5BFB39423C3BB893984033AFE6 /* PSCBOnline-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC99FAA9B0A90B70F4E6F59DF91FE33 /* PSCBOnline-dummy.m */; }; + F52AE2CB1161C30AE4C80DE4D4072F3F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 37A4D1638B2507DEFB76997F27A0726A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DEF6F46953D81544729456672DEB8C3B; + remoteInfo = PSCBOnline; + }; + 8CFFCA919167B6A5449BB2BAE5D0AB0F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E2DB125EC4D0570EFCBF775B921460CD; + remoteInfo = "Pods-PSCBOnlineSample"; + }; + C1D757A49E98C9BC7C322C984D7C7882 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DEF6F46953D81544729456672DEB8C3B; + remoteInfo = PSCBOnline; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 002D20147E567CDBEB2824598F4716CB /* PKPaymentToken+Serializable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PKPaymentToken+Serializable.swift"; path = "PSCBOnline/Sources/Serializable/PKPaymentToken+Serializable.swift"; sourceTree = ""; }; + 07A5FA728F8AB4366597F4A40E03957E /* Pods-PSCBOnlineSample-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PSCBOnlineSample-dummy.m"; sourceTree = ""; }; + 0B60541BCD4B1ADE8420D889E1D5CBBC /* String.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = String.swift; path = PSCBOnline/Sources/Extension/String.swift; sourceTree = ""; }; + 1281087CA1E66877C9B17C2545008FB7 /* Pods-PSCBOnlineSampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSampleTests.release.xcconfig"; sourceTree = ""; }; + 189FD1CBEB8769A50F58E768DD38964F /* Pods_PSCBOnlineSampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_PSCBOnlineSampleTests.framework; path = "Pods-PSCBOnlineSampleTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BC99FAA9B0A90B70F4E6F59DF91FE33 /* PSCBOnline-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PSCBOnline-dummy.m"; sourceTree = ""; }; + 1D5F78C92E6EE2C0F7BDEFCCE8E31ECA /* Pods-PSCBOnlineSample-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSample-acknowledgements.plist"; sourceTree = ""; }; + 202B688F92A9482C65456D1A8A2D79EB /* Pods-PSCBOnlineSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSample.release.xcconfig"; sourceTree = ""; }; + 20E243A5EB4698B0A8D41FF295F7DE3B /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 21D73543BEAE0D2DDAFE272B955D6ACD /* PSCBOnline.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PSCBOnline.debug.xcconfig; sourceTree = ""; }; + 25092117CDF47E1018B6D93F4BABB2FA /* PSCBOnline-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PSCBOnline-Info.plist"; sourceTree = ""; }; + 25654A44F1162BD0643FDB9B306FBA8E /* Pods-PSCBOnlineSampleTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PSCBOnlineSampleTests-acknowledgements.markdown"; sourceTree = ""; }; + 270D42B4EB19C66D7A39FF5F2E0C2B43 /* CustomerData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomerData.swift; path = PSCBOnline/Sources/Models/CustomerData.swift; sourceTree = ""; }; + 2E72013D1FDD07529BFDA1DD586E4A1B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap"; sourceTree = ""; }; + 3D5C736A601CF7F3441804459B3AAF43 /* Pods-PSCBOnlineSampleTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PSCBOnlineSampleTests-umbrella.h"; sourceTree = ""; }; + 40B63E76D69519F459D9BB11D8F07272 /* PSCBOnline-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PSCBOnline-umbrella.h"; sourceTree = ""; }; + 4B5183B110BD9174B18FFF38079FEB02 /* CardData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CardData.swift; path = PSCBOnline/Sources/Models/CardData.swift; sourceTree = ""; }; + 4C5D750DE4FB9525426662E218C20796 /* PSCBOnline.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PSCBOnline.modulemap; sourceTree = ""; }; + 55A13187A86E701DCD971C0A528A814C /* DigestHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DigestHelper.swift; path = PSCBOnline/Sources/Helpers/DigestHelper.swift; sourceTree = ""; }; + 5E8C86CC7D69E4B87AC8AF542842047F /* Pods-PSCBOnlineSampleTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PSCBOnlineSampleTests-dummy.m"; sourceTree = ""; }; + 5F44ECCC00616D9D42F57713A86E39D0 /* RSAHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RSAHelper.swift; path = PSCBOnline/Sources/Helpers/RSAHelper.swift; sourceTree = ""; }; + 60CDD28AD2DDBACF450F4152A9284250 /* Serializable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Serializable.swift; path = PSCBOnline/Sources/Serializable/Serializable.swift; sourceTree = ""; }; + 6F4E90E25A6D567DEEEBFD1C4F45D15D /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m"; sourceTree = ""; }; + 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 766D7A8DB0E03B619C43BBB03FE105E2 /* PSCBAPI.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PSCBAPI.swift; path = PSCBOnline/Sources/PSCBAPI.swift; sourceTree = ""; }; + 7A2E4E6B8D912C02E7B4AB7E039583EE /* Payment.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Payment.swift; path = PSCBOnline/Sources/Models/Payment.swift; sourceTree = ""; }; + 7E7C2E55F1D481F4F7D9CCBF9B5CF1F5 /* Pods-PSCBOnlineSample-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PSCBOnlineSample-umbrella.h"; sourceTree = ""; }; + 862A89FB15BA9064C1382A158D5A7980 /* PSCBOnline.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = PSCBOnline.framework; path = PSCBOnline.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8A3600CD1CB2AC17C9CED8C3D43A8C5F /* Pods-PSCBOnlineSampleTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PSCBOnlineSampleTests.modulemap"; sourceTree = ""; }; + 9524CC825572DBE819487CC420093666 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig"; sourceTree = ""; }; + 964F78D65B05B3AD1ED2298EC279C414 /* PSCBOnline.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PSCBOnline.release.xcconfig; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9ECAF26B7470641EFC17878F4A0DDE76 /* Pods-PSCBOnlineSampleTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSampleTests-acknowledgements.plist"; sourceTree = ""; }; + A140FBF925A6DA8D8E1AA5E483315ADC /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig"; sourceTree = ""; }; + A9AC4D172CDD3DDC2E65569FCA727D3A /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h"; sourceTree = ""; }; + AA42370209FF35773B6B0C7281AF1795 /* PaymentHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PaymentHandler.swift; path = PSCBOnline/Sources/PaymentHandler.swift; sourceTree = ""; }; + AB380BCCFA6B59E92BDD788B999AD5CC /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown"; sourceTree = ""; }; + ACA7FF1BC2F9206FC894DFD51E9D99C4 /* Pods-PSCBOnlineSample-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSample-Info.plist"; sourceTree = ""; }; + B383E2CC977BF6834F6975695A5662AA /* Pods-PSCBOnlineSampleTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSampleTests-Info.plist"; sourceTree = ""; }; + BE932C7A83C19DB4677F1EF18894DE69 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist"; sourceTree = ""; }; + BF9531D3ED1E4E9C21F2AE0C026D64EC /* Payment+Serializable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Payment+Serializable.swift"; path = "PSCBOnline/Sources/Serializable/Payment+Serializable.swift"; sourceTree = ""; }; + C07A1F703F1B2073CAF8027CF10AA4B2 /* Pods-PSCBOnlineSample-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PSCBOnlineSample-acknowledgements.markdown"; sourceTree = ""; }; + C2B81AE6D89092D2AE03A8B4A218EF65 /* Pods-PSCBOnlineSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSample.debug.xcconfig"; sourceTree = ""; }; + CE1F465A2AAE1FD7D58D02B0C9FCEFD6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PSCBOnlineSampleTests.debug.xcconfig"; sourceTree = ""; }; + D302DD80F732D394A15C10B518CA9793 /* RequestWrapper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestWrapper.swift; path = PSCBOnline/Sources/Models/RequestWrapper.swift; sourceTree = ""; }; + DE139BB75A732730123A0FF4C0CB9DDB /* JSONDecoders.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = JSONDecoders.swift; path = PSCBOnline/Sources/Helpers/JSONDecoders.swift; sourceTree = ""; }; + DF17C1ED918A56031196F0EEB88EBAF8 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist"; sourceTree = ""; }; + DFAF349D467D69A30791324875D7FA6A /* Pods-PSCBOnlineSample.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PSCBOnlineSample.modulemap"; sourceTree = ""; }; + E203FA4820121CCEA995CEE6472ADCC6 /* PSCBOnlineClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PSCBOnlineClient.swift; path = PSCBOnline/Sources/PSCBOnlineClient.swift; sourceTree = ""; }; + E79DF10C490F897BAE9C93E7F98A6542 /* Pods-PSCBOnlineSample-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-PSCBOnlineSample-frameworks.sh"; sourceTree = ""; }; + E7C8744A223F4FAA81D82BFA5F315A8B /* PSCBOnline.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PSCBOnline.h; path = PSCBOnline/PSCBOnline.h; sourceTree = ""; }; + E86BD61CBF59BE5420688D690F7110A8 /* PSCBOnline-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PSCBOnline-prefix.pch"; sourceTree = ""; }; + F1543AA141881D8151741C70AEAD76AB /* Pods_PSCBOnlineSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_PSCBOnlineSample.framework; path = "Pods-PSCBOnlineSample.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + F39478722626866FBDA804BD452BFB3B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh"; sourceTree = ""; }; + F6DD36A515037D0DF509ED0DAD6DCABA /* Response.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Response.swift; path = PSCBOnline/Sources/Models/Response.swift; sourceTree = ""; }; + FF470A0A6171E66AF57ACC8C5BDE637B /* RequestWrapper+Serializable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "RequestWrapper+Serializable.swift"; path = "PSCBOnline/Sources/Serializable/RequestWrapper+Serializable.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 763D1C06205F42BEA1A1CFE0D8C8BB71 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F52AE2CB1161C30AE4C80DE4D4072F3F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AFDF9A1AB856CC708266174710086055 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1639B897ACE3EDFA100BC2BA2CDB90F8 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C9FEA5C3739CD0C95377CAD2BF939599 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E473622002751DBAC7B0C7E9659939A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB93FFB23CC96F7B4EA1D01DD87A4594 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C712069DB64560C09EB60BC1CF859A0 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 139198AD913E78566F9BFFCD6A069456 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 7551CD2289AC9C39640091C3502B4225 /* Pods-PSCBOnlineSample */, + 6EC45F85124C022792FF8380CF79D6D1 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests */, + 61C5E1BFC6D540A650D2AF60840B7ABC /* Pods-PSCBOnlineSampleTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 578452D2E740E91742655AC8F1636D1F /* iOS */ = { + isa = PBXGroup; + children = ( + 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 61C5E1BFC6D540A650D2AF60840B7ABC /* Pods-PSCBOnlineSampleTests */ = { + isa = PBXGroup; + children = ( + 8A3600CD1CB2AC17C9CED8C3D43A8C5F /* Pods-PSCBOnlineSampleTests.modulemap */, + 25654A44F1162BD0643FDB9B306FBA8E /* Pods-PSCBOnlineSampleTests-acknowledgements.markdown */, + 9ECAF26B7470641EFC17878F4A0DDE76 /* Pods-PSCBOnlineSampleTests-acknowledgements.plist */, + 5E8C86CC7D69E4B87AC8AF542842047F /* Pods-PSCBOnlineSampleTests-dummy.m */, + B383E2CC977BF6834F6975695A5662AA /* Pods-PSCBOnlineSampleTests-Info.plist */, + 3D5C736A601CF7F3441804459B3AAF43 /* Pods-PSCBOnlineSampleTests-umbrella.h */, + CE1F465A2AAE1FD7D58D02B0C9FCEFD6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */, + 1281087CA1E66877C9B17C2545008FB7 /* Pods-PSCBOnlineSampleTests.release.xcconfig */, + ); + name = "Pods-PSCBOnlineSampleTests"; + path = "Target Support Files/Pods-PSCBOnlineSampleTests"; + sourceTree = ""; + }; + 6EC45F85124C022792FF8380CF79D6D1 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests */ = { + isa = PBXGroup; + children = ( + 2E72013D1FDD07529BFDA1DD586E4A1B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap */, + AB380BCCFA6B59E92BDD788B999AD5CC /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown */, + DF17C1ED918A56031196F0EEB88EBAF8 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist */, + 6F4E90E25A6D567DEEEBFD1C4F45D15D /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m */, + F39478722626866FBDA804BD452BFB3B /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh */, + BE932C7A83C19DB4677F1EF18894DE69 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist */, + A9AC4D172CDD3DDC2E65569FCA727D3A /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h */, + A140FBF925A6DA8D8E1AA5E483315ADC /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */, + 9524CC825572DBE819487CC420093666 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */, + ); + name = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests"; + path = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests"; + sourceTree = ""; + }; + 7551CD2289AC9C39640091C3502B4225 /* Pods-PSCBOnlineSample */ = { + isa = PBXGroup; + children = ( + DFAF349D467D69A30791324875D7FA6A /* Pods-PSCBOnlineSample.modulemap */, + C07A1F703F1B2073CAF8027CF10AA4B2 /* Pods-PSCBOnlineSample-acknowledgements.markdown */, + 1D5F78C92E6EE2C0F7BDEFCCE8E31ECA /* Pods-PSCBOnlineSample-acknowledgements.plist */, + 07A5FA728F8AB4366597F4A40E03957E /* Pods-PSCBOnlineSample-dummy.m */, + E79DF10C490F897BAE9C93E7F98A6542 /* Pods-PSCBOnlineSample-frameworks.sh */, + ACA7FF1BC2F9206FC894DFD51E9D99C4 /* Pods-PSCBOnlineSample-Info.plist */, + 7E7C2E55F1D481F4F7D9CCBF9B5CF1F5 /* Pods-PSCBOnlineSample-umbrella.h */, + C2B81AE6D89092D2AE03A8B4A218EF65 /* Pods-PSCBOnlineSample.debug.xcconfig */, + 202B688F92A9482C65456D1A8A2D79EB /* Pods-PSCBOnlineSample.release.xcconfig */, + ); + name = "Pods-PSCBOnlineSample"; + path = "Target Support Files/Pods-PSCBOnlineSample"; + sourceTree = ""; + }; + AA093FAB843080CA6FDCF0C797075EA6 /* Products */ = { + isa = PBXGroup; + children = ( + F1543AA141881D8151741C70AEAD76AB /* Pods_PSCBOnlineSample.framework */, + 20E243A5EB4698B0A8D41FF295F7DE3B /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */, + 189FD1CBEB8769A50F58E768DD38964F /* Pods_PSCBOnlineSampleTests.framework */, + 862A89FB15BA9064C1382A158D5A7980 /* PSCBOnline.framework */, + ); + name = Products; + sourceTree = ""; + }; + B81AC2CB92F684C1CD91F72B61E36A57 /* Pods */ = { + isa = PBXGroup; + children = ( + EA0C1886EE21C2D1AAFE0D4FD45A9633 /* PSCBOnline */, + ); + name = Pods; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */, + B81AC2CB92F684C1CD91F72B61E36A57 /* Pods */, + AA093FAB843080CA6FDCF0C797075EA6 /* Products */, + 139198AD913E78566F9BFFCD6A069456 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 578452D2E740E91742655AC8F1636D1F /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + EA0C1886EE21C2D1AAFE0D4FD45A9633 /* PSCBOnline */ = { + isa = PBXGroup; + children = ( + 4B5183B110BD9174B18FFF38079FEB02 /* CardData.swift */, + 270D42B4EB19C66D7A39FF5F2E0C2B43 /* CustomerData.swift */, + 55A13187A86E701DCD971C0A528A814C /* DigestHelper.swift */, + DE139BB75A732730123A0FF4C0CB9DDB /* JSONDecoders.swift */, + 7A2E4E6B8D912C02E7B4AB7E039583EE /* Payment.swift */, + BF9531D3ED1E4E9C21F2AE0C026D64EC /* Payment+Serializable.swift */, + AA42370209FF35773B6B0C7281AF1795 /* PaymentHandler.swift */, + 002D20147E567CDBEB2824598F4716CB /* PKPaymentToken+Serializable.swift */, + 766D7A8DB0E03B619C43BBB03FE105E2 /* PSCBAPI.swift */, + E7C8744A223F4FAA81D82BFA5F315A8B /* PSCBOnline.h */, + E203FA4820121CCEA995CEE6472ADCC6 /* PSCBOnlineClient.swift */, + D302DD80F732D394A15C10B518CA9793 /* RequestWrapper.swift */, + FF470A0A6171E66AF57ACC8C5BDE637B /* RequestWrapper+Serializable.swift */, + F6DD36A515037D0DF509ED0DAD6DCABA /* Response.swift */, + 5F44ECCC00616D9D42F57713A86E39D0 /* RSAHelper.swift */, + 60CDD28AD2DDBACF450F4152A9284250 /* Serializable.swift */, + 0B60541BCD4B1ADE8420D889E1D5CBBC /* String.swift */, + EB6937ADE9E65E7EE5DA76FAA9A9883D /* Support Files */, + ); + name = PSCBOnline; + path = PSCBOnline; + sourceTree = ""; + }; + EB6937ADE9E65E7EE5DA76FAA9A9883D /* Support Files */ = { + isa = PBXGroup; + children = ( + 4C5D750DE4FB9525426662E218C20796 /* PSCBOnline.modulemap */, + 1BC99FAA9B0A90B70F4E6F59DF91FE33 /* PSCBOnline-dummy.m */, + 25092117CDF47E1018B6D93F4BABB2FA /* PSCBOnline-Info.plist */, + E86BD61CBF59BE5420688D690F7110A8 /* PSCBOnline-prefix.pch */, + 40B63E76D69519F459D9BB11D8F07272 /* PSCBOnline-umbrella.h */, + 21D73543BEAE0D2DDAFE272B955D6ACD /* PSCBOnline.debug.xcconfig */, + 964F78D65B05B3AD1ED2298EC279C414 /* PSCBOnline.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/PSCBOnline"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 10A0B3BE810B90B3331E0A1B1160F5F5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E481B26E484F433D679AE3C26A849E50 /* Pods-PSCBOnlineSample-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 15ACE53FB1DF78A1FBC7224A2605EAB9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 873C6813FE5DB5C3913FFD8FFFEBCAD9 /* PSCBOnline-umbrella.h in Headers */, + 71803D0B8BC9EC5BA1199DC05D6554D4 /* PSCBOnline.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1FECB87A87535F89CB0089E1E014D464 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 95FFF40AE0BB33405D8CC97AB08E4A38 /* Pods-PSCBOnlineSampleTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7E458D7301AD39050296493E2D0348A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F5D4DFE18ED0AAD59C04E47975E20F7 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3E950DEFA4527CA727310C9636D007AA /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 821254A2699ECCF96583837AE25708A8 /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests" */; + buildPhases = ( + F7E458D7301AD39050296493E2D0348A /* Headers */, + 361683349FA0428DD7AB855D1D99FD9E /* Sources */, + 763D1C06205F42BEA1A1CFE0D8C8BB71 /* Frameworks */, + B61F62746243F8208A240183C99ECEF8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1735BEB63CF0373C1F13373BB0453A55 /* PBXTargetDependency */, + ); + name = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests"; + productName = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests"; + productReference = 20E243A5EB4698B0A8D41FF295F7DE3B /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */; + productType = "com.apple.product-type.framework"; + }; + BFE11DEFCEE6C73419C9155DCB4FE27B /* Pods-PSCBOnlineSampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1AA7291B35DB9D48466B0B89E8BE9D3E /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSampleTests" */; + buildPhases = ( + 1FECB87A87535F89CB0089E1E014D464 /* Headers */, + DCD0EBE8BE1C4029856C7CEB0E24F562 /* Sources */, + C9FEA5C3739CD0C95377CAD2BF939599 /* Frameworks */, + BE63E0D73A70687DD15F51B07CF5FFE4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + DF05A256E61F4E23E3D0A8CABBB51337 /* PBXTargetDependency */, + ); + name = "Pods-PSCBOnlineSampleTests"; + productName = "Pods-PSCBOnlineSampleTests"; + productReference = 189FD1CBEB8769A50F58E768DD38964F /* Pods_PSCBOnlineSampleTests.framework */; + productType = "com.apple.product-type.framework"; + }; + DEF6F46953D81544729456672DEB8C3B /* PSCBOnline */ = { + isa = PBXNativeTarget; + buildConfigurationList = CB032F027FD86C5278ED4A043DF09506 /* Build configuration list for PBXNativeTarget "PSCBOnline" */; + buildPhases = ( + 15ACE53FB1DF78A1FBC7224A2605EAB9 /* Headers */, + F134B92D447DB0D2DD3B409493035DA7 /* Sources */, + AFDF9A1AB856CC708266174710086055 /* Frameworks */, + 3F62045B558EED6E6A05A6010BD64C44 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PSCBOnline; + productName = PSCBOnline; + productReference = 862A89FB15BA9064C1382A158D5A7980 /* PSCBOnline.framework */; + productType = "com.apple.product-type.framework"; + }; + E2DB125EC4D0570EFCBF775B921460CD /* Pods-PSCBOnlineSample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 781F95C22E1C3CABFD280C33D1713725 /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSample" */; + buildPhases = ( + 10A0B3BE810B90B3331E0A1B1160F5F5 /* Headers */, + 43AC7C687F5F0452B8784C3FC1A4B1B8 /* Sources */, + EB93FFB23CC96F7B4EA1D01DD87A4594 /* Frameworks */, + 0D002536F6621F125AC3B90A552B8985 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + AFDD0DD939AAA763CD883E9CB481E8B7 /* PBXTargetDependency */, + ); + name = "Pods-PSCBOnlineSample"; + productName = "Pods-PSCBOnlineSample"; + productReference = F1543AA141881D8151741C70AEAD76AB /* Pods_PSCBOnlineSample.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 10.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = AA093FAB843080CA6FDCF0C797075EA6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E2DB125EC4D0570EFCBF775B921460CD /* Pods-PSCBOnlineSample */, + 3E950DEFA4527CA727310C9636D007AA /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests */, + BFE11DEFCEE6C73419C9155DCB4FE27B /* Pods-PSCBOnlineSampleTests */, + DEF6F46953D81544729456672DEB8C3B /* PSCBOnline */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0D002536F6621F125AC3B90A552B8985 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3F62045B558EED6E6A05A6010BD64C44 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B61F62746243F8208A240183C99ECEF8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BE63E0D73A70687DD15F51B07CF5FFE4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 361683349FA0428DD7AB855D1D99FD9E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E44BDDA6DD7F1183146048FD6C95764 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43AC7C687F5F0452B8784C3FC1A4B1B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13C0ACA010CFDF4876F85B5308F50E1B /* Pods-PSCBOnlineSample-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCD0EBE8BE1C4029856C7CEB0E24F562 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DF10B5E93A702195E92624CA2ED6240C /* Pods-PSCBOnlineSampleTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F134B92D447DB0D2DD3B409493035DA7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 232BCBC67C898EC14B4DE9B1B75991B0 /* CardData.swift in Sources */, + 5F5F26822516C9474E7AD01114879F78 /* CustomerData.swift in Sources */, + D18BBEC284892F81901DFD0BD22B07DC /* DigestHelper.swift in Sources */, + 269AAEA2EB76940DD8E64F0855F4CFFE /* JSONDecoders.swift in Sources */, + BC27C4D84BBCE78CA390FAC2DBD57B26 /* Payment+Serializable.swift in Sources */, + 283419E95C403C3E04992A6FA48BB861 /* Payment.swift in Sources */, + 62268E998A000DAADD5E9BA5D0F2EE6F /* PaymentHandler.swift in Sources */, + 22C319C0A78167ACBCC7E91EE27598C4 /* PKPaymentToken+Serializable.swift in Sources */, + D80F58C566E10DF3FAA7AFAAF3BCFD7B /* PSCBAPI.swift in Sources */, + E63D1F5BFB39423C3BB893984033AFE6 /* PSCBOnline-dummy.m in Sources */, + 1D41A2AE55314D31499ECB25848838D4 /* PSCBOnlineClient.swift in Sources */, + D319206921562386DADE2F3A04553414 /* RequestWrapper+Serializable.swift in Sources */, + 08153B37829081830118DC3FDA1C8891 /* RequestWrapper.swift in Sources */, + DAA505D95F5A8AB9E1A058A0AAB37D62 /* Response.swift in Sources */, + B0C19FDF374038C5043A35C7DBE8946B /* RSAHelper.swift in Sources */, + 238AC86B87F44EB8205349B411A8003C /* Serializable.swift in Sources */, + 725B068C5E0B4AD9FF917A56C6C53049 /* String.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1735BEB63CF0373C1F13373BB0453A55 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PSCBOnline; + target = DEF6F46953D81544729456672DEB8C3B /* PSCBOnline */; + targetProxy = C1D757A49E98C9BC7C322C984D7C7882 /* PBXContainerItemProxy */; + }; + AFDD0DD939AAA763CD883E9CB481E8B7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PSCBOnline; + target = DEF6F46953D81544729456672DEB8C3B /* PSCBOnline */; + targetProxy = 37A4D1638B2507DEFB76997F27A0726A /* PBXContainerItemProxy */; + }; + DF05A256E61F4E23E3D0A8CABBB51337 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Pods-PSCBOnlineSample"; + target = E2DB125EC4D0570EFCBF775B921460CD /* Pods-PSCBOnlineSample */; + targetProxy = 8CFFCA919167B6A5449BB2BAE5D0AB0F /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0464917AC5F154BDCBB4474BE7A23D58 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 21D73543BEAE0D2DDAFE272B955D6ACD /* PSCBOnline.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/PSCBOnline/PSCBOnline-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/PSCBOnline/PSCBOnline-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PSCBOnline/PSCBOnline.modulemap"; + PRODUCT_MODULE_NAME = PSCBOnline; + PRODUCT_NAME = PSCBOnline; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 55646993F4CC60DF2F507B91A4388A08 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 202B688F92A9482C65456D1A8A2D79EB /* Pods-PSCBOnlineSample.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 5FFC240D4EA061896A728F02F65A45CF /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 964F78D65B05B3AD1ED2298EC279C414 /* PSCBOnline.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/PSCBOnline/PSCBOnline-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/PSCBOnline/PSCBOnline-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PSCBOnline/PSCBOnline.modulemap"; + PRODUCT_MODULE_NAME = PSCBOnline; + PRODUCT_NAME = PSCBOnline; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 7EE7A78859F657F6BEFC651185B43192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=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 = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 99466761BC3F29A556F346FFC2D338E5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CE1F465A2AAE1FD7D58D02B0C9FCEFD6 /* Pods-PSCBOnlineSampleTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 9D5356CC1E18A79301D31E9692253E7B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A140FBF925A6DA8D8E1AA5E483315ADC /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + CACF7A9D9D4EDE8DE08794FE6530848A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9524CC825572DBE819487CC420093666 /* Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + D299434AB35E7FD6F7921C8EF24742FF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "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 = 10.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + E1B5448BB6A8709785D27C54A790D3CC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1281087CA1E66877C9B17C2545008FB7 /* Pods-PSCBOnlineSampleTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + FB90144B7CF6629C1911ECE17FA90C3B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C2B81AE6D89092D2AE03A8B4A218EF65 /* Pods-PSCBOnlineSample.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1AA7291B35DB9D48466B0B89E8BE9D3E /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 99466761BC3F29A556F346FFC2D338E5 /* Debug */, + E1B5448BB6A8709785D27C54A790D3CC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D299434AB35E7FD6F7921C8EF24742FF /* Debug */, + 7EE7A78859F657F6BEFC651185B43192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 781F95C22E1C3CABFD280C33D1713725 /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FB90144B7CF6629C1911ECE17FA90C3B /* Debug */, + 55646993F4CC60DF2F507B91A4388A08 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 821254A2699ECCF96583837AE25708A8 /* Build configuration list for PBXNativeTarget "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D5356CC1E18A79301D31E9692253E7B /* Debug */, + CACF7A9D9D4EDE8DE08794FE6530848A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CB032F027FD86C5278ED4A043DF09506 /* Build configuration list for PBXNativeTarget "PSCBOnline" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0464917AC5F154BDCBB4474BE7A23D58 /* Debug */, + 5FFC240D4EA061896A728F02F65A45CF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/PSCBOnline.xcscheme b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/PSCBOnline.xcscheme new file mode 100644 index 0000000..67deaa5 --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/PSCBOnline.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.xcscheme b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.xcscheme new file mode 100644 index 0000000..cb7281d --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample.xcscheme b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample.xcscheme new file mode 100644 index 0000000..d71c670 --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSample.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSampleTests.xcscheme b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSampleTests.xcscheme new file mode 100644 index 0000000..2ccf1d7 --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/Pods-PSCBOnlineSampleTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..f0d1868 --- /dev/null +++ b/PSCBOnlineSample/Pods/Pods.xcodeproj/xcuserdata/oa.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,31 @@ + + + + + SchemeUserState + + PSCBOnline.xcscheme + + isShown + + + Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.xcscheme + + isShown + + + Pods-PSCBOnlineSample.xcscheme + + isShown + + + Pods-PSCBOnlineSampleTests.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-Info.plist b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-dummy.m b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-dummy.m new file mode 100644 index 0000000..7158a46 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PSCBOnline : NSObject +@end +@implementation PodsDummy_PSCBOnline +@end diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-prefix.pch b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-umbrella.h b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-umbrella.h new file mode 100644 index 0000000..fa1c265 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "PSCBOnline.h" + +FOUNDATION_EXPORT double PSCBOnlineVersionNumber; +FOUNDATION_EXPORT const unsigned char PSCBOnlineVersionString[]; + diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.debug.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.debug.xcconfig new file mode 100644 index 0000000..db7e6c1 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PSCBOnline +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.modulemap b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.modulemap new file mode 100644 index 0000000..0ce6c09 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.modulemap @@ -0,0 +1,6 @@ +framework module PSCBOnline { + umbrella header "PSCBOnline-umbrella.h" + + export * + module * { export * } +} diff --git a/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.release.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.release.xcconfig new file mode 100644 index 0000000..db7e6c1 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/PSCBOnline/PSCBOnline.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PSCBOnline +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown new file mode 100644 index 0000000..87be8da --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.markdown @@ -0,0 +1,8 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## PSCBOnline + +LICENSE BE HERE + +Generated by CocoaPods - https://cocoapods.org diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist new file mode 100644 index 0000000..9f7ea6c --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-acknowledgements.plist @@ -0,0 +1,40 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + LICENSE BE HERE + + License + PSCB + Title + PSCBOnline + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m new file mode 100644 index 0000000..587e461 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_PSCBOnlineSample_PSCBOnlineSampleUITests : NSObject +@end +@implementation PodsDummy_Pods_PSCBOnlineSample_PSCBOnlineSampleUITests +@end diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-input-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..c83c9e2 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh +${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-output-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..c0dee12 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-input-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..c83c9e2 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh +${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-output-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..c0dee12 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks-Release-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh new file mode 100644 index 0000000..356ff54 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh @@ -0,0 +1,185 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h new file mode 100644 index 0000000..0e44011 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_PSCBOnlineSample_PSCBOnlineSampleUITestsVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_PSCBOnlineSample_PSCBOnlineSampleUITestsVersionString[]; + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig new file mode 100644 index 0000000..413d190 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.debug.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap new file mode 100644 index 0000000..7e8c2f5 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.modulemap @@ -0,0 +1,6 @@ +framework module Pods_PSCBOnlineSample_PSCBOnlineSampleUITests { + umbrella header "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h" + + export * + module * { export * } +} diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig new file mode 100644 index 0000000..413d190 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.release.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-Info.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.markdown b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.markdown new file mode 100644 index 0000000..87be8da --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.markdown @@ -0,0 +1,8 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## PSCBOnline + +LICENSE BE HERE + +Generated by CocoaPods - https://cocoapods.org diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.plist new file mode 100644 index 0000000..9f7ea6c --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-acknowledgements.plist @@ -0,0 +1,40 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + LICENSE BE HERE + + License + PSCB + Title + PSCBOnline + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-dummy.m b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-dummy.m new file mode 100644 index 0000000..9a2f487 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_PSCBOnlineSample : NSObject +@end +@implementation PodsDummy_Pods_PSCBOnlineSample +@end diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-input-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..7d3e641 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh +${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-output-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..c0dee12 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-input-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..7d3e641 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh +${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-output-files.xcfilelist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..c0dee12 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks-Release-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PSCBOnline.framework \ No newline at end of file diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh new file mode 100644 index 0000000..356ff54 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-frameworks.sh @@ -0,0 +1,185 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-umbrella.h b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-umbrella.h new file mode 100644 index 0000000..74b48b4 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_PSCBOnlineSampleVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_PSCBOnlineSampleVersionString[]; + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.debug.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.debug.xcconfig new file mode 100644 index 0000000..413d190 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.debug.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.modulemap b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.modulemap new file mode 100644 index 0000000..5c51921 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.modulemap @@ -0,0 +1,6 @@ +framework module Pods_PSCBOnlineSample { + umbrella header "Pods-PSCBOnlineSample-umbrella.h" + + export * + module * { export * } +} diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.release.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.release.xcconfig new file mode 100644 index 0000000..413d190 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSample/Pods-PSCBOnlineSample.release.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-Info.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.markdown b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.markdown new file mode 100644 index 0000000..102af75 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.markdown @@ -0,0 +1,3 @@ +# Acknowledgements +This application makes use of the following third party libraries: +Generated by CocoaPods - https://cocoapods.org diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.plist b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.plist new file mode 100644 index 0000000..7acbad1 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-acknowledgements.plist @@ -0,0 +1,29 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-dummy.m b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-dummy.m new file mode 100644 index 0000000..e4df30a --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_PSCBOnlineSampleTests : NSObject +@end +@implementation PodsDummy_Pods_PSCBOnlineSampleTests +@end diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-umbrella.h b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-umbrella.h new file mode 100644 index 0000000..5e00cc6 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_PSCBOnlineSampleTestsVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_PSCBOnlineSampleTestsVersionString[]; + diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.debug.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.debug.xcconfig new file mode 100644 index 0000000..22b5a1f --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.debug.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.modulemap b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.modulemap new file mode 100644 index 0000000..014c306 --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.modulemap @@ -0,0 +1,6 @@ +framework module Pods_PSCBOnlineSampleTests { + umbrella header "Pods-PSCBOnlineSampleTests-umbrella.h" + + export * + module * { export * } +} diff --git a/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.release.xcconfig b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.release.xcconfig new file mode 100644 index 0000000..22b5a1f --- /dev/null +++ b/PSCBOnlineSample/Pods/Target Support Files/Pods-PSCBOnlineSampleTests/Pods-PSCBOnlineSampleTests.release.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PSCBOnline/PSCBOnline.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "PSCBOnline" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/PSCBOnlineTests/Helpers/DigestHelperTests.swift b/PSCBOnlineTests/Helpers/DigestHelperTests.swift new file mode 100644 index 0000000..e666314 --- /dev/null +++ b/PSCBOnlineTests/Helpers/DigestHelperTests.swift @@ -0,0 +1,57 @@ +// +// DigestHelperTests.swift +// PSCB-OOS-iOSTests +// +// Created by OA on 28.10.2020. +// + +import Foundation +import XCTest + +@testable import PSCBOnline + +final class DigestHelperTests: XCTestCase { + + func testSha256_sanity() { + // given: + let str = "" + + // when: + let sha = DigestHelper.sha256String(str) + + // then: + XCTAssertEqual(sha, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + } + + func testSha256_mockSignature() { + // given: + let json = """ + {"payment":{"orderId":"XC-33345","showOrderId":"XC-33345","recurrentable":false,"amount":150.25},"marketPlace":"47607","cardData":"ewogICJwYXltZW50TWV0aG9kIiA6IHsKICAgICJkaXNwbGF5TmFtZSIgOiAiU2ltdWxhdGVkIEluc3RydW1lbnQiLAogICAgIm5ldHdvcmsiIDogIlZpc2EiLAogICAgInR5cGUiIDogImRlYml0IgogIH0sCiAgInRyYW5zYWN0aW9uSWRlbnRpZmllciIgOiAiU2ltdWxhdGVkIElkZW50aWZpZXIiLAogICJwYXltZW50RGF0YSIgOiBudWxsCn0="} + """ + + let salt = "111111" + + // when: + let sha = DigestHelper.sha256String("\(json)\(salt)") + + // then: + XCTAssertEqual(sha, "adbb177db83523ead0e77244afec2d943a3767af401424df56fc951b8bab02e3") + } + + func testMock() { + // given: + let json = """ + {"payment":{"orderId":"XC-33345","showOrderId":"XC-33345","recurrentable":false,"amount":150.25},"marketPlace":"47607","cardData":""} + """ + + let salt = "111111" + + // when: + let sha = DigestHelper.sha256String("\(json)\(salt)") + + // then: + XCTAssertEqual(sha, "8c7c620a70f470a343ff3e9e81496f895a91ffbd6c8a2fef819625794f204908") + + } + +} diff --git a/PSCBOnlineTests/Info.plist b/PSCBOnlineTests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/PSCBOnlineTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/PSCBOnlineTests/Mocks/PassKitMocks.swift b/PSCBOnlineTests/Mocks/PassKitMocks.swift new file mode 100644 index 0000000..c0712b9 --- /dev/null +++ b/PSCBOnlineTests/Mocks/PassKitMocks.swift @@ -0,0 +1,118 @@ +// +// PassKitMocks.swift +// PSCB-OOS-iOSTests +// +// Created by OA on 22.10.2020. +// +#if canImport(PassKit) + +import Foundation +import PassKit + +// MARK: - Mock payment +internal class MockPayment: PKPayment { + + override var token: PKPaymentToken { + return self._token + } + + override var billingContact: PKContact? { + return self._billingContact + } + + override var shippingContact: PKContact? { + return self._shippingContact + } + + override var shippingMethod: PKShippingMethod? { + return self._shippingMethod + } + + let _token: MockPaymentToken + let _billingContact: PKContact? + let _shippingContact: PKContact? + let _shippingMethod: PKShippingMethod? + + init(token: MockPaymentToken, billingContact: PKContact? = nil, shippingContact: PKContact? = nil, shippingMethod: PKShippingMethod? = nil) { + self._token = token + self._billingContact = billingContact + self._shippingContact = shippingContact + self._shippingMethod = shippingMethod + } + + static func createPayment() -> PKPayment { + let token = MockPaymentToken.createToken() + + return MockPayment(token: token as! MockPaymentToken) + } +} + +// MARK: - Mock payment token +internal class MockPaymentToken: PKPaymentToken { + + override var paymentMethod: PKPaymentMethod { + return self._paymentMethod + } + + override var transactionIdentifier: String { + return self._transactionIdentifier + } + + override var paymentData: Data { + return self._paymentData + } + + let _paymentMethod: MockPaymentMethod + let _transactionIdentifier = "2C7B4FD8-7D1B-49D4-8AB5-AFE3CC79265A" + let _paymentData: Data = { + let dict: [AnyHashable: AnyHashable] = [ + "version": "EC_v1", + "data": "....", + "signature": "...." + ] + + return try! JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) + }() + + init(paymentMethod: MockPaymentMethod) { + self._paymentMethod = paymentMethod + } + + static func createToken() -> PKPaymentToken { + return MockPaymentToken(paymentMethod: MockPaymentMethod.createMethod() as! MockPaymentMethod) + } + +} + +// MARK: - Mock payment method +internal class MockPaymentMethod: PKPaymentMethod { + + override var displayName: String? { + return self._displayName + } + + override var network: PKPaymentNetwork? { + return self._network + } + + override var type: PKPaymentMethodType { + return self._type + } + + let _displayName: String? + let _network: PKPaymentNetwork? + let _type: PKPaymentMethodType + + init(type: PKPaymentMethodType, network: PKPaymentNetwork? = nil, displayName: String? = nil) { + self._network = network + self._type = type + self._displayName = displayName + } + + static func createMethod() -> PKPaymentMethod { + return MockPaymentMethod(type: .debit, network: .visa, displayName: "PSCB Visa") + } + +} + +#endif diff --git a/PSCBOnlineTests/PSCBOnlineTests.swift b/PSCBOnlineTests/PSCBOnlineTests.swift new file mode 100644 index 0000000..e92d8c3 --- /dev/null +++ b/PSCBOnlineTests/PSCBOnlineTests.swift @@ -0,0 +1,33 @@ +// +// PSCB_OOS_iOSTests.swift +// PSCB-OOS-iOSTests +// +// Created by OA on 16.10.2020. +// + +import XCTest +@testable import PSCBOnline + +class PSCB_OOS_iOSTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/PSCBOnlineTests/Serializable/PKPaymentToken+SerializableTests.swift b/PSCBOnlineTests/Serializable/PKPaymentToken+SerializableTests.swift new file mode 100644 index 0000000..4531d49 --- /dev/null +++ b/PSCBOnlineTests/Serializable/PKPaymentToken+SerializableTests.swift @@ -0,0 +1,109 @@ +// +// PKPaymentToken+SerializableTests.swift +// PSCB-OOS-iOSTests +// +// Created by Antonov Ilia on 22.10.2020. +// +#if canImport(PassKit) + +import Foundation +import PassKit +import XCTest + +@testable import PSCBOnline + +final class PKPaymentTokenSerializableTests: XCTestCase { + + // MARK: - Test .serializeToJSON() + func testPaymentTokenSerialization() { + // given: + let token = MockPaymentToken.createToken() + + // when: + let json = token.serializeToJSON() + + print("JSON: >>") + print(json) + + // then: + XCTAssertEqual(json["transactionIdentifier"], "2C7B4FD8-7D1B-49D4-8AB5-AFE3CC79265A") + + // and: + let method = json["paymentMethod"] + let network = (method as! [String: AnyHashable])["network"] ?? "N/A" as AnyHashable + XCTAssertEqual(network, "Visa" as AnyHashable) + } + + // MARK: - Test .serializeToData() + func testSerializeToData() { + // given: + let token = MockPaymentToken.createToken() + + // expect: + XCTAssertNoThrow(try token.serializeToData()) + } + + // MARK: - Test .serializeToString() + func testSerializeToString() { + // given: + let token = MockPaymentToken.createToken() + + // expect: + XCTAssertNoThrow(try token.serializeToString()) + + // when: + let json = try! token.serializeToString() + + // debug: + print("JSON: >>") + print(json) + } + + // MARK: - Test PKPaymentToken.toCryptogramString() + func testToCryptogramString() { + // given: + let token = MockPaymentToken.createToken() + + // expect: + XCTAssertNoThrow(try token.toCryptogramString()) + + // when: + let string = try! token.toCryptogramString() + + // debug: + print("Cryptogram String: >> \(string)") + + // then: + XCTAssertFalse(string.isEmpty) + + // when: + let data = Data(base64Encoded: string, options: Data.Base64DecodingOptions(rawValue: 0))! + + // debug: + print("Decoded >>") + print(String(data: data, encoding: .utf8)!) + + // and: + let decoder = JSONDecoder() + let output = try! decoder.decode(PaymentTokenResult.self, from: data) + + // then: + XCTAssertEqual(output.version, "EC_v1") + XCTAssertEqual(output.signature, "....") + } + +} + +internal struct PaymentTokenResult: Decodable { + let data: String + let version: String + let signature: String +} + +internal struct PaymentMethodResult: Decodable { + let displayName: String + let network: String + let type: String +} + +#endif diff --git a/PSCBOnlineTests/Serializable/PKPaymentTokenTests.swift b/PSCBOnlineTests/Serializable/PKPaymentTokenTests.swift new file mode 100644 index 0000000..012e92a --- /dev/null +++ b/PSCBOnlineTests/Serializable/PKPaymentTokenTests.swift @@ -0,0 +1,35 @@ +// +// PKPaymentTokenTests.swift +// PSCB-OOS-iOSTests +// +// Created by Antonov Ilia on 22.10.2020. +// +#if canImport(PassKit) + +import Foundation +import PassKit +import XCTest + +@testable import PSCBOnline + +final class PKPaymentTokenTests: XCTestCase { + + func testToCryptogramString() { + // given: + let token = MockPaymentToken.createToken() + + // expect: No exception is thrown on creating a string + XCTAssertNoThrow(try token.toCryptogramString()) + + // when: + let cryptogram = try! token.toCryptogramString() + + print(">> Cryptogram string: \(cryptogram)") + + // then: + XCTAssertFalse(cryptogram.isEmpty) + } + +} + +#endif diff --git a/PSCBOnlineTests/Sources/Models/CardDataTests.swift b/PSCBOnlineTests/Sources/Models/CardDataTests.swift new file mode 100644 index 0000000..aebe925 --- /dev/null +++ b/PSCBOnlineTests/Sources/Models/CardDataTests.swift @@ -0,0 +1,47 @@ +// +// CardDataTests.swift +// PSCB-OOS-iOSTests +// +// Created by Antonov Ilia on 26.10.2020. +// + +import Foundation +import XCTest + +@testable import PSCBOnline + +final class CardDataTests: XCTestCase { + + internal static let testCard = CardData( + pan: "4200111122223333", + expiryYear: 2017, + expiryMonth: 5, + cvCode: "123", + cardholder: "IVANOV IVAN" + )! + + func testSanity() { + // given: + let card = Self.testCard + + // expect: + XCTAssertEqual("05", card.getExpMonthString()) + XCTAssertEqual("17", card.getExpYearString()) + } + + func testCryptogram() { + // given: + let card = Self.testCard + + // expect: + XCTAssertNoThrow(try card.toCryptgramString()) + + // when: + let string = try! card.toCryptgramString() + + // then: + XCTAssertFalse(string.isEmpty) + XCTAssertTrue(string.count == 88) + } + +} diff --git a/PSCBOnlineTests/Sources/Models/PaymentTests.swift b/PSCBOnlineTests/Sources/Models/PaymentTests.swift new file mode 100644 index 0000000..6e05cfa --- /dev/null +++ b/PSCBOnlineTests/Sources/Models/PaymentTests.swift @@ -0,0 +1,36 @@ +// +// PaymentTests.swift +// PSCB-OOS-iOSTests +// +// Created by OA on 12.10.2020. +// + +import Foundation +import XCTest + +@testable import PSCBOnline + +final class PaymentTests: XCTestCase { + + func testEncoding() { + // given: + let payment = Payment.example + let encoder = JSONEncoder() + + // expect: + XCTAssertNoThrow(try encoder.encode(payment)) + + // when: + let json = try? encoder.encode(payment) + let string = String(data: json ?? Data(), encoding: .utf8)! + + // then: + print("----") + print(string) + + XCTAssertEqual(string, """ + {"amount":150,"orderId":"\(payment.orderId)","recurrentable":false,"details":"Wonderful warm socks","customerAccount":"ID-12345","showOrderId":"\(payment.showOrderId!)","customerPhone":"+7 900 000 00 00","customerEmail":"foo@bar.com","customerComment":"By tomorrow please"} + """) + } + +} diff --git a/PSCBOnlineTests/Sources/Models/ResponseTests.swift b/PSCBOnlineTests/Sources/Models/ResponseTests.swift new file mode 100644 index 0000000..295b3b0 --- /dev/null +++ b/PSCBOnlineTests/Sources/Models/ResponseTests.swift @@ -0,0 +1,117 @@ +// +// ResponseTests.swift +// PSCB-OOS-iOSTests +// +// Created by Antonov Ilia on 23.10.2020. +// + +import Foundation +import XCTest + +@testable import PSCBOnline + +final class ResponseTests: XCTestCase { + + private let mockResponse: String = { + return """ + { + "status":"STATUS_SUCCESS", + "requestId":"PROD-141024-103898B", + "payment":{ + "orderId":"1111103", + "showOrderId":"1111103", + "paymentId":"8067739", + "account":"shpa", + "amount":1350.89, + "state":"sent", + "marketPlace":47607, + "paymentMethod":"ac-shpa", + "stateDate":"2014-10-24T10:38:40.501+04:00" + }, + "PaReq":"eJydk01TgzAQhu/+CgbPkpBihU6IU60fVWmr4jjjxcnAjkXLRwN12n/", + "order":"22040229", + "TermUrl":"https://oos.pscb.ru/merchantApi/confirmShpa", + "URL":"https://acs.multicarta.ru/PaReqVISA.jsp", + "MD":"NTJmZTFjMWEtNjQ0Mi00ODQ2LTlkMjMtZDU0MzdkYzA0N2Fk" + } + """ + }() + + private let anotherMockResponse: String = { + """ + {"status":"STATUS_SUCCESS","requestId":"DEMO-201102-1652-2BE12","payment":{"orderId":"XC-33353","showOrderId":"XC-33353","paymentId":"229359620","account":null,"amount":155.35,"state":"end","marketPlace":12345,"paymentMethod":"ac-shpa","stateDate":"2020-11-02T16:52:16.563+03:00"},"description":"Payment processed successfully"} + """ + }() + + private let dateFormatter: DateFormatter = { + let fmtString = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" + let formatter = DateFormatter() + + formatter.dateFormat = fmtString + return formatter + }() + + func testDecodeResponse() { + // given: + let responseData = mockResponse.data(using: .utf8)! + let decoder = JSONDecoders.iso8601DateAwareDecoder() + + // expect: + XCTAssertNoThrow(try decoder.decode(Response.self, from: responseData)) + + // when: + let response = try! decoder.decode(Response.self, from: responseData) + + // then: + XCTAssertEqual(response.requestId, "PROD-141024-103898B") + XCTAssertEqual(response.status, .success) + + // when: + let payment = response.payment! + + // then: + XCTAssertEqual(payment.state, .sent) + XCTAssertEqual(payment.amount, Decimal(1350.89)) + XCTAssertEqual(payment.marketPlace, 47607) + XCTAssertEqual(payment.orderId, "1111103") + XCTAssertEqual(payment.showOrderId, "1111103") + XCTAssertEqual(payment.stateDate, dateFormatter.date(from: "2014-10-24T10:38:40.501+04:00")) + XCTAssertEqual(payment.paymentId, "8067739") + + // when: + let acquiringData = response.acquiringData + + // then: + XCTAssertEqual(acquiringData?.order, "22040229") + } + + func testDecodeResponse_another() { + // given: + let responseData = anotherMockResponse.data(using: .utf8)! + let decoder = JSONDecoders.iso8601DateAwareDecoder() + + // expect: + XCTAssertNoThrow(try decoder.decode(Response.self, from: responseData)) + + // when: + let response = try! decoder.decode(Response.self, from: responseData) + + // then: + XCTAssertEqual(response.requestId, "DEMO-201102-1652-2BE12") + XCTAssertEqual(response.status, .success) + XCTAssertEqual(response.description, "Payment processed successfully") + + // when: + let payment = response.payment! + + // then: + XCTAssertEqual(payment.state, .end) + XCTAssertEqual(payment.amount, Decimal(155.35)) + XCTAssertEqual(payment.marketPlace, 12345) + XCTAssertEqual(payment.orderId, "XC-33353") + XCTAssertEqual(payment.showOrderId, "XC-33353") + XCTAssertEqual(payment.stateDate, dateFormatter.date(from: "2020-11-02T16:52:16.563+03:00")) + XCTAssertEqual(payment.paymentId, "229359620") + } + +} diff --git a/PSCBOnlineTests/Sources/OOSAPIClientTests.swift b/PSCBOnlineTests/Sources/OOSAPIClientTests.swift new file mode 100644 index 0000000..0a11011 --- /dev/null +++ b/PSCBOnlineTests/Sources/OOSAPIClientTests.swift @@ -0,0 +1,114 @@ +// +// OOSAPIClientTests.swift +// PSCB-OOS-iOSTests +// +// Created by Antonov Ilia on 21.10.2020. +// +#if canImport(PassKit) + +import Foundation +import PassKit +import XCTest + +@testable import PSCBOnline + +final class OOSAPIClientTests: XCTestCase { + + static let marketPlaceId = "1234567" + + let subject = PSCBOnlineClient(environment: .sandbox, marketPlaceId: marketPlaceId, signingKey: "foobar") + + // MARK: - OOS Payment request for PKPayment + func testCreatingRequestWrapper_PKPayment() { + // given: + let amount = Decimal(100) + let orderId = "123" + let payment = Self.createMockPayment() + + // expect: No exception thrown + XCTAssertNoThrow(try subject.makeRequestWithPayment(payment: payment, amount: amount, orderId: orderId)) + + // when: + let request = try! subject.makeRequestWithPayment(payment: payment, amount: amount, orderId: orderId) + + // then: Values equals + XCTAssertEqual(amount, request.payment.amount) + XCTAssertEqual(orderId, request.payment.orderId) + XCTAssertEqual(Self.marketPlaceId, request.marketPlaceId) + + print("CardData : \(String(describing: request.cardData))") + + // and: Card data is ApplePayCardData + // XCTAssertTrue(request.cardData) + } + + // MARK: - OOS Payment request for CardData + func testCreatingRequestWrapper_CardData() { + // given: + let amount = Decimal(100) + let orderId = "123" + let payment = Payment(amount: amount, orderId: orderId) + let card = Self.createMockCard() + + // expect: No exception thrown + XCTAssertNoThrow(try subject.makeRequestWithCardData(card: card, payment: payment)) + + // when: + let request = try! subject.makeRequestWithCardData(card: card, payment: payment) + + // then: Values equals + XCTAssertEqual(amount, request.payment.amount) + XCTAssertEqual(orderId, request.payment.orderId) + XCTAssertEqual(Self.marketPlaceId, request.marketPlaceId) + + print("CardData : \(String(describing: request.cardData))") + + // and: Card data is ApplePayCardData + // XCTAssertTrue(request.cardData) + } + + // MARK: - Checking JSON from encoded data + func testEncodingPaymentRequest() { + // givent: + let amount = Decimal(100) + let orderId = "1234" + let payment = Self.createMockPayment() + + // and: + let request = try! subject.makeRequestWithPayment(payment: payment, amount: amount, orderId: orderId) + + // expect: + XCTAssertNoThrow(try request.serializeToString()) + + // when: + let jsonString = try! request.serializeToString() + + print("JSON Request: \(jsonString)") + + // then: + XCTAssertTrue(!jsonString.isEmpty) + } + + + private static func createMockPayment() -> PKPayment { + let paymentMethod = MockPaymentMethod(type: .debit, network: .visa, displayName: "PSCB Visa") + let token = MockPaymentToken(paymentMethod: paymentMethod) + + return MockPayment(token: token) + } + + private static func createMockCard() -> CardData { + let current = Date() + let calendar = Calendar.current + + return CardData( + pan: "4761120010000492", + expiryYear: calendar.component(.year, from: current) + 1, + expiryMonth: calendar.component(.month, from: current), + cvCode: "533" + )! + } + +} + +#endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..94dbb5d --- /dev/null +++ b/README.md @@ -0,0 +1,217 @@ +# ПСКБ Платежи iOS SDK + +[![Platform](https://img.shields.io/badge/Support-iOS%2010.0+-brightgreen.svg)](https://img.shields.io/badge/Support-iOS%2010.3+-brightgreen.svg) + +Библиотека является дополнением к API системы интернет-эквайринга [ПСКБ "Платежи"](https://online.pscb.ru) +и позволяет подключить приём платежей по картам в мобильных приложениях iOS с минимальными усилиями. + +## Возможности + +На текущий момент библиотека поддерживает: + + - Apple Pay + - Оплата картами + +## Подключение зависимостей + +1. Установите CocoaPods 1.10.0 или выше + +```zsh +gem install cocoapods +``` +[Официальная документация по установке CocoaPods](https://guides.cocoapods.org/using/getting-started.html) + +2.  Создайте в своём приложении `Podfile` + +Это также можно сделать при помощи команды `pod init` , находясь в директории своего проекта. (В таком случае будет создан `Podfile` с настройками по умолчанию) + +3. Добавьте зависимости в `Podfile` + +```ruby +platform :ios, '10.0' + +target '' do + use_frameworks! + + pod 'PSCBOnline', :git => "https://git2dev.pscb.ru/pscb-dev/pscbonline-ios", :tag => "1.0.0" + +end +``` + +> `` - Название проекта вашего приложения в XCode + +4. Выполните команду `pod install` + +## Интеграция + +1. Для работы с библиотекой импортируйте зависимости в нужный файл проекта: + +```swift +import PSCBOnline +``` + +2. Создайте экземпляр `PSCBOnlineClient` с вашими настройками: + +```swift +let apiClient = PSCBOnlineClient( + environment: .sandbox, + marketPlaceId: "", + signingKey: "" +) +``` + +> `environment` -  окружение, в рамках которого библиотека взаимодействует с сервисом. `.sandbox` - тестовое окружение; `.production` - продуктовое. +> `Your MarketPlace ID` - ваш идентификатор в системе ПСКБ-Онлайн. +> `Your Signing Key` - ваш ключ подписи запросов к системе. + +3. Создайте экземпляр `Payment` + +```swift +let payment = Payment(amount: Decimal(1000.00), orderId: "Order-ID") +``` +> `amount` - сумма в рублях. (_На текущий момент другая валюта не поддерживается._) +> `orderId` - уникальный идентификатор заказа в рамках магазина. + +_Для детальной информации, какие параметры принимает смотрите документацию `Payment`._ + +---- + +Дальнейшая интеграция отличается от способа оплаты. + +## Доступные способы оплаты + +Сейчас в SDK доступна оплата: + + - Банковкой кратой + - Apple Pay + + Для их настройки реализации смотрите дальше. + +### Приём оплаты банковскимикартами + +1. Для приёма оплаты картами нужно создать экземпляр класса `CardData`. + +```swift +let card = CardData( + pan: "4761349750010326", + expiryYear: 2022, + expiryMonth: 12, + cvCode: "851" +) +``` + +2. Создать токен запроса, используя экземпляр `PSCBOnlineClient`, созданный ранее. + +```swift +let request = try! client.makeRequestWithCardData(card: card, payment: payment) +``` + +3. Отправить токен запроса на сервер ПСКБ-Онлайн. + +```swift +// Send request to backend +client.send(request, responseHandler: { (error, response) in + guard nil == error && nil != response else { + print("Error sending request: \(String(describing: error))") + return + } + + print("Successful request:") + print(response!) +}) +``` + +> В случае успешного выполнения запроса, `response` будет содержать информацию о принятом платеже, его ID, состояние и прочие данные. + +### Приём оплаты Apple Pay + +Для приёма платежей через Apple Pay вы должны зарегестрировать Merchant ID в Apple. + +Помимо `merchant ID` необходимо настроить сертификат обработки запросов (`Payment Processing Certificate`) и передать его ПСКБ-Онлайн. Этим сертификатом Apple будет шифровать данные банковских карт перед отправкой на сервер ПСКБ-Онлайн. + +Все пререквизиты описаны на сайте [официальной документации Apple](https://developer.apple.com/documentation/passkit/apple_pay/setting_up_apple_pay_requirements). + +Также вы можете ознакомиться сподробной инструкцией на сайте документации [ПСКБ Онлайн](https://docs.pscb.ru/oos/advanced.html#dopolnitelnye-opcii-apple-pay). + +--- + +После выполнения пререквизитов, в коде необходимо: + +1. Импортировать `PassKit`: + +```swift +import PassKit +``` + +2. Создать экземпляр класса `PKPaymentAuthorizationController` и настроить делегирующий класс `PKPaymentAuthorizationControllerDelegate`: + +Пример: + +```swift +import PassKit +import PSCBOnline + +class ApplePayHandler: NSObject { + + public func handleApplePay(payment: Payment) { + // Позиции оплаты для представления пользователя + let items = [PKPaymentSummaryItem(label: "Shoes", amount: NSDecimalNumber(intergerLiteral: 1000))] + + // Запрос на оплату для PKPaymentAuthorizationController + let paymentRequest = PSCBAPI.makePaymentRequest(merchantId: "", items: []) + + // Вызов модуля оплаты + let authorizationController = PKPaymentAuthorizationController(paymentRequest: paymentRequest) + + authorizationController?.delegate = self + authorizationController?.present(completion: { presented in + if presented { + print("Controller presented") + } else { + print("Controller could not be presented") + } + }) + } +} + +extension ApplePayHandler: PKPaymentAuthorizationControllerDelegate { + + public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, + didAuthorizePayment payment: PKPayment, + handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { + + // 1. + // Вызывается после авторизации платежа плательщиком биометрическими данными или паролем + } + + public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { + // 2. + // Вызывается после того, как платёж совершён или пользователь закрыл модуль оплаты. + } + +} +``` + +> `` - Ваш идентификатор мерчанта. + +3. Далее в примере выше в п.1 и п.2 реализовать необходимую логику отправки запроса на сервер ПСКБ-Онлайн. + Для пункта 1 - это создание токена запроса (используя `client.makeRequestWithPayment(pkPayment, pscbPayment)` и отправка его на сервер: + +```swift +// Request token +let request = try! client.makeRequestWithPayment(pkPayment: pkPayment, pscbPayment: payment) + +// Sending request to backend +client.send(request, responseHandler: { (error, response) in + if (error == nil && response != nil) { + completion(PKPaymentAuthorizationResult(status: .success, errors: nil)) + } else { + print("Error sending payment: \(String(describing: error))") + completion(PKPaymentAuthorizationResult(status: .failure, errors: nil)) + } +}) +``` + +4. А для пункта 2 - обработка закрытия модуля оплаты. + +## Описание классов и параметров diff --git a/Untitled.xcworkspace/contents.xcworkspacedata b/Untitled.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..cdda1a9 --- /dev/null +++ b/Untitled.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/Untitled.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Untitled.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Untitled.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Untitled.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate b/Untitled.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..dbe9dc4 Binary files /dev/null and b/Untitled.xcworkspace/xcuserdata/oa.xcuserdatad/UserInterfaceState.xcuserstate differ