This commit is contained in:
pscb-dev 2024-07-08 15:20:00 +03:00
commit 4cc1b4cca5
132 changed files with 8242 additions and 0 deletions

1
LICENSE.txt Normal file
View File

@ -0,0 +1 @@
LICENSE BE HERE

138
PSCBOnline.podspec Normal file
View File

@ -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

View File

@ -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 = "<group>"; };
0E01EAAE25399CB500B0759B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
0E01EABA25399CB500B0759B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0E01EACC25399DB000B0759B /* Payment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Payment.swift; sourceTree = "<group>"; };
0E01EAD225399DF500B0759B /* CustomerData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerData.swift; sourceTree = "<group>"; };
0E01EAD725399E3D00B0759B /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
0E01EADD25399E8800B0759B /* RequestWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestWrapper.swift; sourceTree = "<group>"; };
0E01EAE325399EE800B0759B /* PaymentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentTests.swift; sourceTree = "<group>"; };
0E0A2C1E25408AA1006BBBA1 /* CardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardData.swift; sourceTree = "<group>"; };
0E0A2C22254093D0006BBBA1 /* Payment+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Payment+Serializable.swift"; sourceTree = "<group>"; };
0E26F5852542FB5800F80DAC /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
0E26F5892542FE2000F80DAC /* ResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseTests.swift; sourceTree = "<group>"; };
0E26F58E2545AE5800F80DAC /* JSONDecoders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONDecoders.swift; sourceTree = "<group>"; };
0E26F59E2547097300F80DAC /* RSAHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSAHelper.swift; sourceTree = "<group>"; };
0E26F5A2254714B600F80DAC /* CardDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardDataTests.swift; sourceTree = "<group>"; };
0E26F5E72548717B00F80DAC /* PSCBAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSCBAPI.swift; sourceTree = "<group>"; };
0E26F62D2549591D00F80DAC /* DigestHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigestHelper.swift; sourceTree = "<group>"; };
0E26F63225495A5B00F80DAC /* DigestHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigestHelperTests.swift; sourceTree = "<group>"; };
0E547EB32552BEA500E0F8C0 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
0E790FA2253DEA930086AD71 /* PSCBOnline.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PSCBOnline.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
0E790FAA253E017E0086AD71 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
0EA2C84D2539A5BA00C5DD14 /* Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Serializable.swift; sourceTree = "<group>"; };
0EA2C8572539F4D500C5DD14 /* PSCBOnlineClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSCBOnlineClient.swift; sourceTree = "<group>"; };
0EA2C8612539FAC200C5DD14 /* PaymentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentHandler.swift; sourceTree = "<group>"; };
0EA2C869253B29A900C5DD14 /* PKPaymentToken+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PKPaymentToken+Serializable.swift"; sourceTree = "<group>"; };
0EA2C871253CC44A00C5DD14 /* RequestWrapper+Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RequestWrapper+Serializable.swift"; sourceTree = "<group>"; };
0EC9DB062540A1C8005392A0 /* OOSAPIClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOSAPIClientTests.swift; sourceTree = "<group>"; };
0EC9DB0B2541B699005392A0 /* PassKitMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassKitMocks.swift; sourceTree = "<group>"; };
0EC9DB122541BF45005392A0 /* PKPaymentToken+SerializableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PKPaymentToken+SerializableTests.swift"; sourceTree = "<group>"; };
0EC9DB182541D9F9005392A0 /* PKPaymentTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKPaymentTokenTests.swift; sourceTree = "<group>"; };
/* 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 = "<group>";
};
0E01EAAB25399CB500B0759B /* Products */ = {
isa = PBXGroup;
children = (
0E01EAAA25399CB500B0759B /* PSCBOnline.framework */,
0E01EAB325399CB500B0759B /* PSCBOnlineTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
0E01EAAC25399CB500B0759B /* PSCBOnline */ = {
isa = PBXGroup;
children = (
0E01EAC625399CEF00B0759B /* Sources */,
0E01EAAD25399CB500B0759B /* PSCBOnline.h */,
0E01EAAE25399CB500B0759B /* Info.plist */,
);
path = PSCBOnline;
sourceTree = "<group>";
};
0E01EAB725399CB500B0759B /* PSCBOnlineTests */ = {
isa = PBXGroup;
children = (
0E26F63125495A2F00F80DAC /* Helpers */,
0EC9DB112541BF2D005392A0 /* Serializable */,
0EC9DB0A2541B686005392A0 /* Mocks */,
0E01EAE125399ECE00B0759B /* Sources */,
0E01EAB825399CB500B0759B /* PSCBOnlineTests.swift */,
0E01EABA25399CB500B0759B /* Info.plist */,
);
path = PSCBOnlineTests;
sourceTree = "<group>";
};
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 = "<group>";
};
0E01EACB25399D8F00B0759B /* Models */ = {
isa = PBXGroup;
children = (
0E01EACC25399DB000B0759B /* Payment.swift */,
0E01EAD225399DF500B0759B /* CustomerData.swift */,
0E01EADD25399E8800B0759B /* RequestWrapper.swift */,
0E0A2C1E25408AA1006BBBA1 /* CardData.swift */,
0E26F5852542FB5800F80DAC /* Response.swift */,
);
path = Models;
sourceTree = "<group>";
};
0E01EAD625399E0F00B0759B /* Extension */ = {
isa = PBXGroup;
children = (
0E01EAD725399E3D00B0759B /* String.swift */,
);
path = Extension;
sourceTree = "<group>";
};
0E01EAE125399ECE00B0759B /* Sources */ = {
isa = PBXGroup;
children = (
0E01EAE225399ED400B0759B /* Models */,
0EC9DB062540A1C8005392A0 /* OOSAPIClientTests.swift */,
);
path = Sources;
sourceTree = "<group>";
};
0E01EAE225399ED400B0759B /* Models */ = {
isa = PBXGroup;
children = (
0E01EAE325399EE800B0759B /* PaymentTests.swift */,
0E26F5892542FE2000F80DAC /* ResponseTests.swift */,
0E26F5A2254714B600F80DAC /* CardDataTests.swift */,
);
path = Models;
sourceTree = "<group>";
};
0E26F58D2545AE4200F80DAC /* Helpers */ = {
isa = PBXGroup;
children = (
0E26F58E2545AE5800F80DAC /* JSONDecoders.swift */,
0E26F59E2547097300F80DAC /* RSAHelper.swift */,
0E26F62D2549591D00F80DAC /* DigestHelper.swift */,
);
path = Helpers;
sourceTree = "<group>";
};
0E26F63125495A2F00F80DAC /* Helpers */ = {
isa = PBXGroup;
children = (
0E26F63225495A5B00F80DAC /* DigestHelperTests.swift */,
);
path = Helpers;
sourceTree = "<group>";
};
0EA2C84C2539A5A300C5DD14 /* Serializable */ = {
isa = PBXGroup;
children = (
0EA2C84D2539A5BA00C5DD14 /* Serializable.swift */,
0EA2C869253B29A900C5DD14 /* PKPaymentToken+Serializable.swift */,
0EA2C871253CC44A00C5DD14 /* RequestWrapper+Serializable.swift */,
0E0A2C22254093D0006BBBA1 /* Payment+Serializable.swift */,
);
path = Serializable;
sourceTree = "<group>";
};
0EC9DB0A2541B686005392A0 /* Mocks */ = {
isa = PBXGroup;
children = (
0EC9DB0B2541B699005392A0 /* PassKitMocks.swift */,
);
path = Mocks;
sourceTree = "<group>";
};
0EC9DB112541BF2D005392A0 /* Serializable */ = {
isa = PBXGroup;
children = (
0EC9DB122541BF45005392A0 /* PKPaymentToken+SerializableTests.swift */,
0EC9DB182541D9F9005392A0 /* PKPaymentTokenTests.swift */,
);
path = Serializable;
sourceTree = "<group>";
};
/* 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 */;
}

View File

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

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>PSCBOnline.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>0E01EAA925399CB500B0759B</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>0E01EAB225399CB500B0759B</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

22
PSCBOnline/Info.plist Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>

18
PSCBOnline/PSCBOnline.h Normal file
View File

@ -0,0 +1,18 @@
//
// PSCBOnline.h
// PSCBOnline
//
// Created by Antonov Ilia on 16.10.2020.
//
#import <Foundation/Foundation.h>
//! 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 <PSCBOnline/PublicHeader.h>

View File

@ -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..<length {
let randInt = arc4random_uniform(UInt32(seq.count))
rnd += "\(seq[seq.index(seq.startIndex, offsetBy: Int(randInt))])"
}
return rnd
}
}

View File

@ -0,0 +1,29 @@
//
// DigestHelper.swift
// PSCB-OOS-iOS
//
// Created by Antonov Ilia on 28.10.2020.
//
import Foundation
import CommonCrypto
public struct DigestHelper {
public static func sha256String(_ string: String) -> 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()
}
}

View File

@ -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)
}
}

View File

@ -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<CFError>)
}
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<CFError>? = 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()
}
}

View File

@ -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
}
}

View File

@ -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"
}
}

View File

@ -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?
// <Not in use>
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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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<T: RawRepresentable>(key: T, nullable value: JSONDict.Value?) where T.RawValue == JSONDict.Key {
// if let value = value {
// self.updateValue(value, forKey: key.rawValue)
// }
// }
//
//}

View File

@ -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 = "<group>"; };
0ECA01DA254C88BF003DBD74 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
0ECA01DC254C88BF003DBD74 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
0ECA01DE254C88C4003DBD74 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0ECA01E1254C88C4003DBD74 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
0ECA01E4254C88C4003DBD74 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
0ECA01E6254C88C4003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
0ECA01F1254C88C5003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
0ECA01FC254C88C5003DBD74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0ECA020B254C8902003DBD74 /* sdk.sample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = sdk.sample.entitlements; sourceTree = "<group>"; };
0ECA0217254C8C12003DBD74 /* Podfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
0ECA0236254C8DA0003DBD74 /* PaymentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentHandler.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
/* 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 = "<group>";
};
0ECA01D6254C88BF003DBD74 /* Products */ = {
isa = PBXGroup;
children = (
0ECA01D5254C88BF003DBD74 /* PSCBOnlineSample.app */,
0ECA01EB254C88C5003DBD74 /* PSCBOnlineSampleTests.xctest */,
0ECA01F6254C88C5003DBD74 /* PSCBOnlineSampleUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
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 = "<group>";
};
0ECA01E0254C88C4003DBD74 /* Preview Content */ = {
isa = PBXGroup;
children = (
0ECA01E1254C88C4003DBD74 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
0ECA01EE254C88C5003DBD74 /* PSCBOnlineSampleTests */ = {
isa = PBXGroup;
children = (
0ECA01EF254C88C5003DBD74 /* sdk_sampleTests.swift */,
0ECA01F1254C88C5003DBD74 /* Info.plist */,
);
path = PSCBOnlineSampleTests;
sourceTree = "<group>";
};
0ECA01F9254C88C5003DBD74 /* PSCBOnlineSampleUITests */ = {
isa = PBXGroup;
children = (
0ECA01FA254C88C5003DBD74 /* sdk_sampleUITests.swift */,
0ECA01FC254C88C5003DBD74 /* Info.plist */,
);
path = PSCBOnlineSampleUITests;
sourceTree = "<group>";
};
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 = "<group>";
};
CC92252B44ABB68C5546B8DC /* Frameworks */ = {
isa = PBXGroup;
children = (
ADAE0E73DFA819AE992A9C59 /* Pods_PSCBOnlineSample.framework */,
215AD129A382ED26BE4A9ADC /* Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework */,
75E713AE69B50BE64C2D03E8 /* Pods_PSCBOnlineSampleTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* 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 = "<group>";
};
/* 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 */;
}

View File

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

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ECA01D4254C88BF003DBD74"
BuildableName = "PSCBOnlineSample.app"
BlueprintName = "PSCBOnlineSample"
ReferencedContainer = "container:PSCBOnlineSample.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ECA01EA254C88C5003DBD74"
BuildableName = "PSCBOnlineSampleTests.xctest"
BlueprintName = "PSCBOnlineSampleTests"
ReferencedContainer = "container:PSCBOnlineSample.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ECA01F5254C88C5003DBD74"
BuildableName = "PSCBOnlineSampleUITests.xctest"
BlueprintName = "PSCBOnlineSampleUITests"
ReferencedContainer = "container:PSCBOnlineSample.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ECA01D4254C88BF003DBD74"
BuildableName = "PSCBOnlineSample.app"
BlueprintName = "PSCBOnlineSample"
ReferencedContainer = "container:PSCBOnlineSample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ECA01D4254C88BF003DBD74"
BuildableName = "PSCBOnlineSample.app"
BlueprintName = "PSCBOnlineSample"
ReferencedContainer = "container:PSCBOnlineSample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>PSCBOnlineSample.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>sdk.sample.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>0ECA01D4254C88BF003DBD74</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>0ECA01EA254C88C5003DBD74</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>0ECA01F5254C88C5003DBD74</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:PSCBOnlineSample.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,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<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}

View File

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,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()
}
}

View File

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

View File

@ -0,0 +1,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
}
}
}
}

View File

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

View File

@ -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.
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array/>
<key>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.pscb.pay</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -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.
}
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -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 its 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()
}
}
}
}

View File

@ -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

View File

@ -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"
}

22
PSCBOnlineSample/Pods/Manifest.lock generated Normal file
View File

@ -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

View File

@ -0,0 +1 @@
LICENSE BE HERE

View File

@ -0,0 +1,18 @@
//
// PSCBOnline.h
// PSCBOnline
//
// Created by Antonov Ilia on 16.10.2020.
//
#import <Foundation/Foundation.h>
//! 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 <PSCBOnline/PublicHeader.h>

View File

@ -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..<length {
let randInt = arc4random_uniform(UInt32(seq.count))
rnd += "\(seq[seq.index(seq.startIndex, offsetBy: Int(randInt))])"
}
return rnd
}
}

View File

@ -0,0 +1,29 @@
//
// DigestHelper.swift
// PSCB-OOS-iOS
//
// Created by Antonov Ilia on 28.10.2020.
//
import Foundation
import CommonCrypto
public struct DigestHelper {
public static func sha256String(_ string: String) -> 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()
}
}

View File

@ -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)
}
}

View File

@ -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<CFError>)
}
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<CFError>? = 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()
}
}

View File

@ -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
}
}

View File

@ -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"
}
}

View File

@ -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?
// <Not in use>
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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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<T: RawRepresentable>(key: T, nullable value: JSONDict.Value?) where T.RawValue == JSONDict.Key {
// if let value = value {
// self.updateValue(value, forKey: key.rawValue)
// }
// }
//
//}

217
PSCBOnlineSample/Pods/PSCBOnline/README.md generated Normal file
View File

@ -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 '<Target name>' do
use_frameworks!
pod 'PSCBOnline', :git => "https://bitbucket.org/dev_ai/pscbonline.git", :tag => "1.0.0"
end
```
> `<Target name>` - Название проекта вашего приложения в XCode
4. Выполните команду `pod install`
## Интеграция
1. Для работы с библиотекой импортируйте зависимости в нужный файл проекта:
```swift
import PSCBOnline
```
2. Создайте экземпляр `PSCBOnlineClient` с вашими настройками:
```swift
let apiClient = PSCBOnlineClient(
environment: .sandbox,
marketPlaceId: "<Your MarketPlace ID>",
signingKey: "<Your Signing Key>"
)
```
> `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: "<Your Apple Merchant ID>", 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.
// Вызывается после того, как платёж совершён или пользователь закрыл модуль оплаты.
}
}
```
> `<Your Apple Merchant ID>` - Ваш идентификатор мерчанта.
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 - обработка закрытия модуля оплаты.
## Описание классов и параметров

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DEF6F46953D81544729456672DEB8C3B"
BuildableName = "PSCBOnline.framework"
BlueprintName = "PSCBOnline"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3E950DEFA4527CA727310C9636D007AA"
BuildableName = "Pods_PSCBOnlineSample_PSCBOnlineSampleUITests.framework"
BlueprintName = "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E2DB125EC4D0570EFCBF775B921460CD"
BuildableName = "Pods_PSCBOnlineSample.framework"
BlueprintName = "Pods-PSCBOnlineSample"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BFE11DEFCEE6C73419C9155DCB4FE27B"
BuildableName = "Pods_PSCBOnlineSampleTests.framework"
BlueprintName = "Pods-PSCBOnlineSampleTests"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>PSCBOnline.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>Pods-PSCBOnlineSample-PSCBOnlineSampleUITests.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>Pods-PSCBOnlineSample.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>Pods-PSCBOnlineSampleTests.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict/>
</dict>
</plist>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_PSCBOnline : NSObject
@end
@implementation PodsDummy_PSCBOnline
@end

View File

@ -0,0 +1,12 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

View File

@ -0,0 +1,17 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#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[];

View File

@ -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

View File

@ -0,0 +1,6 @@
framework module PSCBOnline {
umbrella header "PSCBOnline-umbrella.h"
export *
module * { export * }
}

View File

@ -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

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -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

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>LICENSE BE HERE
</string>
<key>License</key>
<string>PSCB</string>
<key>Title</key>
<string>PSCBOnline</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_PSCBOnlineSample_PSCBOnlineSampleUITests : NSObject
@end
@implementation PodsDummy_Pods_PSCBOnlineSample_PSCBOnlineSampleUITests
@end

View File

@ -0,0 +1,2 @@
${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh
${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework

View File

@ -0,0 +1 @@
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PSCBOnline.framework

View File

@ -0,0 +1,2 @@
${PODS_ROOT}/Target Support Files/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests/Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-frameworks.sh
${BUILT_PRODUCTS_DIR}/PSCBOnline/PSCBOnline.framework

View File

@ -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

View File

@ -0,0 +1,16 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#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[];

View File

@ -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

View File

@ -0,0 +1,6 @@
framework module Pods_PSCBOnlineSample_PSCBOnlineSampleUITests {
umbrella header "Pods-PSCBOnlineSample-PSCBOnlineSampleUITests-umbrella.h"
export *
module * { export * }
}

View File

@ -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

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -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

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>LICENSE BE HERE
</string>
<key>License</key>
<string>PSCB</string>
<key>Title</key>
<string>PSCBOnline</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More