Permalink
Browse files

StoreKit

  • Loading branch information...
1 parent bb9c70b commit ee28b3cec9d30ee6f572e2ad44976dcfb2c690d0 Erica Sadun committed Sep 4, 2009
Showing with 3,496 additions and 0 deletions.
  1. BIN C20-StoreKit/01-Products Request/Default.png
  2. +257 −0 C20-StoreKit/01-Products Request/HelloWorld.xcodeproj/project.pbxproj
  3. +8 −0 C20-StoreKit/01-Products Request/HelloWorld_Prefix.pch
  4. +26 −0 C20-StoreKit/01-Products Request/Info.plist
  5. +223 −0 C20-StoreKit/01-Products Request/TestBedViewController.xib
  6. +33 −0 C20-StoreKit/01-Products Request/UIDevice-Reachability.h
  7. +273 −0 C20-StoreKit/01-Products Request/UIDevice-Reachability.m
  8. BIN C20-StoreKit/01-Products Request/cover320x416.png
  9. BIN C20-StoreKit/01-Products Request/icon.png
  10. +119 −0 C20-StoreKit/01-Products Request/main.m
  11. BIN C20-StoreKit/02-Purchase/Default.png
  12. +263 −0 C20-StoreKit/02-Purchase/HelloWorld.xcodeproj/project.pbxproj
  13. +8 −0 C20-StoreKit/02-Purchase/HelloWorld_Prefix.pch
  14. +26 −0 C20-StoreKit/02-Purchase/Info.plist
  15. +15 −0 C20-StoreKit/02-Purchase/ModalAlert.h
  16. +180 −0 C20-StoreKit/02-Purchase/ModalAlert.m
  17. +223 −0 C20-StoreKit/02-Purchase/TestBedViewController.xib
  18. +33 −0 C20-StoreKit/02-Purchase/UIDevice-Reachability.h
  19. +273 −0 C20-StoreKit/02-Purchase/UIDevice-Reachability.m
  20. BIN C20-StoreKit/02-Purchase/cover320x416.png
  21. BIN C20-StoreKit/02-Purchase/icon.png
  22. +180 −0 C20-StoreKit/02-Purchase/main.m
  23. BIN C20-StoreKit/03-Validating Receipt/Default.png
  24. +269 −0 C20-StoreKit/03-Validating Receipt/HelloWorld.xcodeproj/project.pbxproj
  25. +8 −0 C20-StoreKit/03-Validating Receipt/HelloWorld_Prefix.pch
  26. +26 −0 C20-StoreKit/03-Validating Receipt/Info.plist
  27. +15 −0 C20-StoreKit/03-Validating Receipt/ModalAlert.h
  28. +180 −0 C20-StoreKit/03-Validating Receipt/ModalAlert.m
  29. +15 −0 C20-StoreKit/03-Validating Receipt/NSData-Base64.h
  30. +112 −0 C20-StoreKit/03-Validating Receipt/NSData-Base64.m
  31. +223 −0 C20-StoreKit/03-Validating Receipt/TestBedViewController.xib
  32. +33 −0 C20-StoreKit/03-Validating Receipt/UIDevice-Reachability.h
  33. +273 −0 C20-StoreKit/03-Validating Receipt/UIDevice-Reachability.m
  34. BIN C20-StoreKit/03-Validating Receipt/cover320x416.png
  35. BIN C20-StoreKit/03-Validating Receipt/icon.png
  36. +202 −0 C20-StoreKit/03-Validating Receipt/main.m
View
BIN C20-StoreKit/01-Products Request/Default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
257 C20-StoreKit/01-Products Request/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,257 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; };
+ 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
+ 8E3A1F090FAA199F009B0518 /* cover320x416.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E3A1F080FAA199F009B0518 /* cover320x416.png */; };
+ 8E4156E90FA4EE0E0006D27C /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E70FA4EE0E0006D27C /* Default.png */; };
+ 8E4156EA0FA4EE0E0006D27C /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E80FA4EE0E0006D27C /* icon.png */; };
+ 8E785FCB0FCDB853006EA81F /* TestBedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */; };
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */; };
+ 8EFD3CAD10518F16007BACA7 /* UIDevice-Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */; };
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 32CA4F630368D1EE00C91783 /* HelloWorld_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelloWorld_Prefix.pch; sourceTree = "<group>"; };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 8E3A1F080FAA199F009B0518 /* cover320x416.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cover320x416.png; sourceTree = "<group>"; };
+ 8E4156E70FA4EE0E0006D27C /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
+ 8E4156E80FA4EE0E0006D27C /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
+ 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TestBedViewController.xib; sourceTree = "<group>"; };
+ 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ 8EFD3CAB10518F16007BACA7 /* UIDevice-Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice-Reachability.h"; sourceTree = "<group>"; };
+ 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice-Reachability.m"; sourceTree = "<group>"; };
+ 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = "../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks/SystemConfiguration.framework"; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1D60588F0D05DD3D006BFB54 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */,
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */,
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97316FDCFA39411CA2CEA /* main.m */,
+ 8EB688610FA64AD100489E4B /* Support */,
+ 29B97323FDCFA39411CA2CEA /* Frameworks */,
+ 19C28FACFE9D520D11CA2CBB /* Products */,
+ );
+ name = CustomTemplate;
+ sourceTree = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */,
+ 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */,
+ 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */,
+ 1D30AB110D05D00D00671497 /* Foundation.framework */,
+ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 8EB688610FA64AD100489E4B /* Support */ = {
+ isa = PBXGroup;
+ children = (
+ 8EFD3CAB10518F16007BACA7 /* UIDevice-Reachability.h */,
+ 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */,
+ 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */,
+ 8E3A1F080FAA199F009B0518 /* cover320x416.png */,
+ 32CA4F630368D1EE00C91783 /* HelloWorld_Prefix.pch */,
+ 8D1107310486CEB800E47090 /* Info.plist */,
+ 8E4156E80FA4EE0E0006D27C /* icon.png */,
+ 8E4156E70FA4EE0E0006D27C /* Default.png */,
+ );
+ name = Support;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 1D6058900D05DD3D006BFB54 /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ 1D60588D0D05DD3D006BFB54 /* Resources */,
+ 1D60588E0D05DD3D006BFB54 /* Sources */,
+ 1D60588F0D05DD3D006BFB54 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = HelloWorld;
+ productReference = 1D6058910D05DD3D006BFB54 /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 1D6058900D05DD3D006BFB54 /* HelloWorld */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 1D60588D0D05DD3D006BFB54 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8E4156E90FA4EE0E0006D27C /* Default.png in Resources */,
+ 8E4156EA0FA4EE0E0006D27C /* icon.png in Resources */,
+ 8E3A1F090FAA199F009B0518 /* cover320x416.png in Resources */,
+ 8E785FCB0FCDB853006EA81F /* TestBedViewController.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 1D60588E0D05DD3D006BFB54 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1D60589B0D05DD56006BFB54 /* main.m in Sources */,
+ 8EFD3CAD10518F16007BACA7 /* UIDevice-Reachability.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1D6058940D05DD3E006BFB54 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Erica Sadun";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks\"",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = HelloWorld_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ PREBINDING = NO;
+ PRODUCT_NAME = HelloWorld;
+ };
+ name = Debug;
+ };
+ 1D6058950D05DD3E006BFB54 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks\"",
+ );
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = HelloWorld_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ PREBINDING = NO;
+ PRODUCT_NAME = HelloWorld;
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+ C01FCF4F08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CODE_SIGN_IDENTITY = "Erica Sadun";
+ "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ PRODUCT_NAME = "Oh Hello";
+ SDKROOT = iphoneos2.0;
+ };
+ name = Debug;
+ };
+ C01FCF5008A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ PREBINDING = NO;
+ SDKROOT = iphoneos2.0;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1D6058940D05DD3E006BFB54 /* Debug */,
+ 1D6058950D05DD3E006BFB54 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4F08A954540054247B /* Debug */,
+ C01FCF5008A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
View
8 C20-StoreKit/01-Products Request/HelloWorld_Prefix.pch
@@ -0,0 +1,8 @@
+//
+// Prefix header for all source files of the 'HelloWorld' target in the 'HelloWorld' project
+//
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+ #import <UIKit/UIKit.h>
+#endif
View
26 C20-StoreKit/01-Products Request/Info.plist
@@ -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>CFBundleDisplayName</key>
+ <string>StoreKitDemo</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.sadun.Scanner</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
View
223 C20-StoreKit/01-Products Request/TestBedViewController.xib
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.03">
+ <data>
+ <int key="IBDocument.SystemTarget">768</int>
+ <string key="IBDocument.SystemVersion">9J61</string>
+ <string key="IBDocument.InterfaceBuilderVersion">680</string>
+ <string key="IBDocument.AppKitVersion">949.46</string>
+ <string key="IBDocument.HIToolboxVersion">353.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="35"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="372490531">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ </object>
+ <object class="IBProxyObject" id="843779117">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ </object>
+ <object class="IBUIView" id="440620744">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">292</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIImageView" id="1064941195">
+ <reference key="NSNextResponder" ref="440620744"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{320, 416}</string>
+ <reference key="NSSuperview" ref="440620744"/>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <int key="IBUIContentMode">4</int>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <object class="NSCustomResource" key="IBUIImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">cover320x416.png</string>
+ </object>
+ </object>
+ <object class="IBUITextView" id="311618606">
+ <reference key="NSNextResponder" ref="440620744"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrameSize">{320, 279}</string>
+ <reference key="NSSuperview" ref="440620744"/>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <bool key="IBUIShowsHorizontalScrollIndicator">NO</bool>
+ <bool key="IBUIDelaysContentTouches">NO</bool>
+ <bool key="IBUICanCancelContentTouches">NO</bool>
+ <bool key="IBUIBouncesZoom">NO</bool>
+ <bool key="IBUIEditable">NO</bool>
+ <string key="IBUIText"/>
+ <object class="IBUITextInputTraits" key="IBUITextInputTraits">
+ <int key="IBUIAutocapitalizationType">2</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{320, 416}</string>
+ <reference key="NSSuperview"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ <object class="NSColorSpace" key="NSCustomColorSpace">
+ <int key="NSID">2</int>
+ </object>
+ </object>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+ <object class="IBUISimulatedNavigationBarMetrics" key="IBUISimulatedTopBarMetrics">
+ <bool key="IBUIPrompted">NO</bool>
+ </object>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">view</string>
+ <reference key="source" ref="372490531"/>
+ <reference key="destination" ref="440620744"/>
+ </object>
+ <int key="connectionID">33</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">textView</string>
+ <reference key="source" ref="372490531"/>
+ <reference key="destination" ref="311618606"/>
+ </object>
+ <int key="connectionID">36</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="884947135">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="372490531"/>
+ <reference key="parent" ref="884947135"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="843779117"/>
+ <reference key="parent" ref="884947135"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">32</int>
+ <reference key="object" ref="440620744"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1064941195"/>
+ <reference ref="311618606"/>
+ </object>
+ <reference key="parent" ref="884947135"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">34</int>
+ <reference key="object" ref="1064941195"/>
+ <reference key="parent" ref="440620744"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">35</int>
+ <reference key="object" ref="311618606"/>
+ <reference key="parent" ref="440620744"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.CustomClassName</string>
+ <string>-2.CustomClassName</string>
+ <string>32.IBEditorWindowLastContentRect</string>
+ <string>32.IBPluginDependency</string>
+ <string>35.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>TestBedViewController</string>
+ <string>UIResponder</string>
+ <string>{{21, 492}, {320, 480}}</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">36</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">TestBedViewController</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>textView</string>
+ <string>view</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UITextView</string>
+ <string>UIView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">HelloWorld.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <string key="IBCocoaTouchPluginVersion">3.1</string>
+ </data>
+</archive>
View
33 C20-StoreKit/01-Products Request/UIDevice-Reachability.h
@@ -0,0 +1,33 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License for anything not specifically marked as developed by a third party.
+ Apple's code excluded.
+ Use at your own risk
+ */
+
+#import <UIKit/UIKit.h>
+
+@protocol ReachabilityWatcher <NSObject>
+- (void) reachabilityChanged;
+@end
+
+@interface UIDevice (Reachability)
++ (NSString *) stringFromAddress: (const struct sockaddr *) address;
++ (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address;
+
++ (NSString *) hostname;
++ (NSString *) getIPAddressForHost: (NSString *) theHost;
++ (NSString *) localIPAddress;
++ (NSString *) localWiFiIPAddress;
++ (NSString *) whatismyipdotcom;
+
++ (BOOL) hostAvailable: (NSString *) theHost;
++ (BOOL) networkAvailable;
++ (BOOL) activeWLAN;
++ (BOOL) activeWWAN;
++ (BOOL) performWiFiCheck;
+
++ (BOOL) scheduleReachabilityWatcher: (id) watcher;
++ (void) unscheduleReachabilityWatcher;
+@end
View
273 C20-StoreKit/01-Products Request/UIDevice-Reachability.m
@@ -0,0 +1,273 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License for anything not specifically marked as developed by a third party.
+ Apple's code excluded.
+ Use at your own risk
+ */
+
+#import <SystemConfiguration/SystemConfiguration.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#import <dlfcn.h>
+#import "UIDevice-Reachability.h"
+
+@implementation UIDevice (Reachability)
+SCNetworkConnectionFlags connectionFlags;
+SCNetworkReachabilityRef reachability;
+
+#pragma mark Class IP and Host Utilities
+// This IP Utilities are mostly inspired by or derived from Apple code. Thank you Apple.
+
++ (NSString *) stringFromAddress: (const struct sockaddr *) address
+{
+ if(address && address->sa_family == AF_INET) {
+ const struct sockaddr_in* sin = (struct sockaddr_in*) address;
+ return [NSString stringWithFormat:@"%@:%d", [NSString stringWithUTF8String:inet_ntoa(sin->sin_addr)], ntohs(sin->sin_port)];
+ }
+
+ return nil;
+}
+
++ (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
+{
+ if (!IPAddress || ![IPAddress length]) {
+ return NO;
+ }
+
+ memset((char *) address, sizeof(struct sockaddr_in), 0);
+ address->sin_family = AF_INET;
+ address->sin_len = sizeof(struct sockaddr_in);
+
+ int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
+ if (conversionResult == 0) {
+ NSAssert1(conversionResult != 1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
+ return NO;
+ }
+
+ return YES;
+}
+
++ (NSString *) hostname
+{
+ char baseHostName[255];
+ int success = gethostname(baseHostName, 255);
+ if (success != 0) return nil;
+ baseHostName[255] = '\0';
+
+ #if !TARGET_IPHONE_SIMULATOR
+ return [NSString stringWithFormat:@"%s.local", baseHostName];
+ #else
+ return [NSString stringWithFormat:@"%s", baseHostName];
+ #endif
+}
+
++ (NSString *) getIPAddressForHost: (NSString *) theHost
+{
+ struct hostent *host = gethostbyname([theHost UTF8String]);
+ if (!host) {herror("resolv"); return NULL; }
+ struct in_addr **list = (struct in_addr **)host->h_addr_list;
+ NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0]) encoding:NSUTF8StringEncoding];
+ return addressString;
+}
+
++ (NSString *) localIPAddress
+{
+ struct hostent *host = gethostbyname([[self hostname] UTF8String]);
+ if (!host) {herror("resolv"); return nil;}
+ struct in_addr **list = (struct in_addr **)host->h_addr_list;
+ return [NSString stringWithCString:inet_ntoa(*list[0]) encoding:NSUTF8StringEncoding];
+}
+
+// Matt Brown's get WiFi IP addy solution
+// Author gave permission to use in Cookbook under cookbook license
+// http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html
++ (NSString *) localWiFiIPAddress
+{
+ BOOL success;
+ struct ifaddrs * addrs;
+ const struct ifaddrs * cursor;
+
+ success = getifaddrs(&addrs) == 0;
+ if (success) {
+ cursor = addrs;
+ while (cursor != NULL) {
+ // the second test keeps from picking up the loopback address
+ if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0)
+ {
+ NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
+ if ([name isEqualToString:@"en0"]) // Wi-Fi adapter
+ return [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
+ }
+ cursor = cursor->ifa_next;
+ }
+ freeifaddrs(addrs);
+ }
+ return nil;
+}
+
++ (NSString *) whatismyipdotcom
+{
+ NSError *error;
+ NSURL *ipURL = [NSURL URLWithString:@"http://www.whatismyip.com/automation/n09230945.asp"];
+ NSString *ip = [NSString stringWithContentsOfURL:ipURL encoding:1 error:&error];
+ return ip ? ip : [error localizedDescription];
+}
+
++ (BOOL) hostAvailable: (NSString *) theHost
+{
+
+ NSString *addressString = [self getIPAddressForHost:theHost];
+ if (!addressString)
+ {
+ printf("Error recovering IP address from host name\n");
+ return NO;
+ }
+
+ struct sockaddr_in address;
+ BOOL gotAddress = [self addressFromString:addressString address:&address];
+
+ if (!gotAddress)
+ {
+ printf("Error recovering sockaddr address from %s\n", [addressString UTF8String]);
+ return NO;
+ }
+
+ SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&address);
+ SCNetworkReachabilityFlags flags;
+
+ BOOL didRetrieveFlags =SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
+ CFRelease(defaultRouteReachability);
+
+ if (!didRetrieveFlags)
+ {
+ printf("Error. Could not recover network reachability flags\n");
+ return NO;
+ }
+
+ BOOL isReachable = flags & kSCNetworkFlagsReachable;
+ return isReachable ? YES : NO;;
+}
+
+#pragma mark Checking Connections
+
++ (void) pingReachabilityInternal
+{
+ if (!reachability)
+ {
+ BOOL ignoresAdHocWiFi = NO;
+ struct sockaddr_in ipAddress;
+ bzero(&ipAddress, sizeof(ipAddress));
+ ipAddress.sin_len = sizeof(ipAddress);
+ ipAddress.sin_family = AF_INET;
+ ipAddress.sin_addr.s_addr = htonl(ignoresAdHocWiFi ? INADDR_ANY : IN_LINKLOCALNETNUM);
+
+ /* Can also create zero addy
+ struct sockaddr_in zeroAddress;
+ bzero(&zeroAddress, sizeof(zeroAddress));
+ zeroAddress.sin_len = sizeof(zeroAddress);
+ zeroAddress.sin_family = AF_INET; */
+
+ reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&ipAddress);
+ CFRetain(reachability);
+ }
+
+ // Recover reachability flags
+ BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(reachability, &connectionFlags);
+ if (!didRetrieveFlags) printf("Error. Could not recover network reachability flags\n");
+}
+
++ (BOOL) networkAvailable
+{
+ [self pingReachabilityInternal];
+ BOOL isReachable = ((connectionFlags & kSCNetworkFlagsReachable) != 0);
+ BOOL needsConnection = ((connectionFlags & kSCNetworkFlagsConnectionRequired) != 0);
+ return (isReachable && !needsConnection) ? YES : NO;
+}
+
++ (BOOL) activeWWAN
+{
+ if (![self networkAvailable]) return NO;
+ return ((connectionFlags & kSCNetworkReachabilityFlagsIsWWAN) != 0);
+}
+
++ (BOOL) activeWLAN
+{
+ return ([UIDevice localWiFiIPAddress] != nil);
+}
+
+
+#pragma mark WiFi Check and Alert
++ (void) showAlert: (id) formatstring,...
+{
+ va_list arglist;
+ if (!formatstring) return;
+ va_start(arglist, formatstring);
+ id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];
+ va_end(arglist);
+
+ UIAlertView *av = [[[UIAlertView alloc] initWithTitle:outstring message:nil delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];
+ [av show];
+}
+
++ (BOOL) performWiFiCheck
+{
+ if (![self networkAvailable] || ![self activeWLAN])
+ {
+ [self performSelector:@selector(showAlert:) withObject:@"This application requires WiFi. Please enable WiFi in Settings and run this application again." afterDelay:0.5f];
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark Monitoring reachability
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* info)
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ [(id)info performSelector:@selector(reachabilityChanged)];
+ [pool release];
+}
+
++ (BOOL) scheduleReachabilityWatcher: (id) watcher
+{
+ if (![watcher conformsToProtocol:@protocol(ReachabilityWatcher)])
+ {
+ NSLog(@"Watcher must conform to ReachabilityWatcher protocol. Cannot continue.");
+ return NO;
+ }
+
+ [self pingReachabilityInternal];
+
+ SCNetworkReachabilityContext context = {0, watcher, NULL, NULL, NULL};
+ if(SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context))
+ {
+ if(!SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes))
+ {
+ NSLog(@"Error: Could not schedule reachability");
+ SCNetworkReachabilitySetCallback(reachability, NULL, NULL);
+ return NO;
+ }
+ }
+ else
+ {
+ NSLog(@"Error: Could not set reachability callback");
+ return NO;
+ }
+
+ return YES;
+}
+
++ (void) unscheduleReachabilityWatcher
+{
+ SCNetworkReachabilitySetCallback(reachability, NULL, NULL);
+ if (SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes))
+ NSLog(@"Unscheduled reachability");
+ else
+ NSLog(@"Error: Could not unschedule reachability");
+
+ CFRelease(reachability);
+ reachability = nil;
+}
+@end
View
BIN C20-StoreKit/01-Products Request/cover320x416.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN C20-StoreKit/01-Products Request/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
119 C20-StoreKit/01-Products Request/main.m
@@ -0,0 +1,119 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+#import <UIKit/UIKit.h>
+#import <StoreKit/StoreKit.h>
+#import "UIDevice-Reachability.h"
+
+#define COOKBOOK_PURPLE_COLOR [UIColor colorWithRed:0.20392f green:0.19607f blue:0.61176f alpha:1.0f]
+#define BARBUTTON(TITLE, SELECTOR) [[[UIBarButtonItem alloc] initWithTitle:TITLE style:UIBarButtonItemStylePlain target:self action:SELECTOR] autorelease]
+
+#define PRODUCT_ID @"com.sadun.scanner.disclosure2"
+#define SANDBOX YES
+
+@interface TestBedViewController : UIViewController <SKProductsRequestDelegate>
+{
+ NSMutableString *log;
+ IBOutlet UITextView *textView;
+}
+@property (retain) NSMutableString *log;
+@property (retain) UITextView *textView;
+@end
+
+@implementation TestBedViewController
+@synthesize log;
+@synthesize textView;
+
+- (void) doLog: (NSString *) formatstring, ...
+{
+ va_list arglist;
+ if (!formatstring) return;
+ va_start(arglist, formatstring);
+ NSString *outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];
+ va_end(arglist);
+ [self.log appendString:outstring];
+ [self.log appendString:@"\n"];
+ self.textView.text = self.log;
+}
+
+- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
+{
+ [self doLog:@"Error: Could not contact App Store properly, %@", [error localizedDescription]];
+}
+
+- (void)requestDidFinish:(SKRequest *)request
+{
+ // Release the request
+ [request release];
+ [self doLog:@"Request finished."];
+}
+
+- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
+{
+ // Find a product
+ SKProduct *product = [[response products] lastObject];
+ if (!product)
+ {
+ [self doLog:@"Error: Could not find matching products"];
+ return;
+ }
+
+ // Retrieve the localized price
+ NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
+ [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
+ [numberFormatter setLocale:product.priceLocale];
+ NSString *formattedString = [numberFormatter stringFromNumber:product.price];
+ [numberFormatter release];
+
+ // Show the information
+ [self doLog:product.localizedTitle];
+ [self doLog:product.localizedDescription];
+ [self doLog:@"Price: %@", formattedString];
+}
+
+- (void) action: (UIBarButtonItem *) bbi
+{
+ // Init log
+ self.log = [NSMutableString string];
+ [self doLog:@"Submitting Request... Please wait."];
+
+ // Create the product request and start it
+ SKProductsRequest *preq = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:PRODUCT_ID]];
+ preq.delegate = self;
+ [preq start];
+}
+
+- (void) viewDidLoad
+{
+ self.navigationController.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
+ self.navigationItem.rightBarButtonItem = BARBUTTON(@"Action", @selector(action:));
+
+ self.log = [NSMutableString string];
+ if (![UIDevice networkAvailable])
+ [self doLog:@"You are not connected to the network! All StoreKit calls will fail!"];
+}
+@end
+
+@interface TestBedAppDelegate : NSObject <UIApplicationDelegate>
+@end
+
+@implementation TestBedAppDelegate
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+ UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[TestBedViewController alloc] init]];
+ [window addSubview:nav.view];
+ [window makeKeyAndVisible];
+}
+@end
+
+int main(int argc, char *argv[])
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int retVal = UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
+ [pool release];
+ return retVal;
+}
View
BIN C20-StoreKit/02-Purchase/Default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
263 C20-StoreKit/02-Purchase/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,263 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; };
+ 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
+ 8E3A1F090FAA199F009B0518 /* cover320x416.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E3A1F080FAA199F009B0518 /* cover320x416.png */; };
+ 8E4156E90FA4EE0E0006D27C /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E70FA4EE0E0006D27C /* Default.png */; };
+ 8E4156EA0FA4EE0E0006D27C /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E80FA4EE0E0006D27C /* icon.png */; };
+ 8E785FCB0FCDB853006EA81F /* TestBedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */; };
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */; };
+ 8EFD3CAD10518F16007BACA7 /* UIDevice-Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */; };
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */; };
+ 8EFD3D5A1051977F007BACA7 /* ModalAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3D591051977F007BACA7 /* ModalAlert.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 32CA4F630368D1EE00C91783 /* HelloWorld_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelloWorld_Prefix.pch; sourceTree = "<group>"; };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 8E3A1F080FAA199F009B0518 /* cover320x416.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cover320x416.png; sourceTree = "<group>"; };
+ 8E4156E70FA4EE0E0006D27C /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
+ 8E4156E80FA4EE0E0006D27C /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
+ 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TestBedViewController.xib; sourceTree = "<group>"; };
+ 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ 8EFD3CAB10518F16007BACA7 /* UIDevice-Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice-Reachability.h"; sourceTree = "<group>"; };
+ 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice-Reachability.m"; sourceTree = "<group>"; };
+ 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = "../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks/SystemConfiguration.framework"; sourceTree = SOURCE_ROOT; };
+ 8EFD3D581051977F007BACA7 /* ModalAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalAlert.h; sourceTree = "<group>"; };
+ 8EFD3D591051977F007BACA7 /* ModalAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalAlert.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1D60588F0D05DD3D006BFB54 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */,
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */,
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97316FDCFA39411CA2CEA /* main.m */,
+ 8EB688610FA64AD100489E4B /* Support */,
+ 29B97323FDCFA39411CA2CEA /* Frameworks */,
+ 19C28FACFE9D520D11CA2CBB /* Products */,
+ );
+ name = CustomTemplate;
+ sourceTree = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */,
+ 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */,
+ 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */,
+ 1D30AB110D05D00D00671497 /* Foundation.framework */,
+ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 8EB688610FA64AD100489E4B /* Support */ = {
+ isa = PBXGroup;
+ children = (
+ 8EFD3D581051977F007BACA7 /* ModalAlert.h */,
+ 8EFD3D591051977F007BACA7 /* ModalAlert.m */,
+ 8EFD3CAB10518F16007BACA7 /* UIDevice-Reachability.h */,
+ 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */,
+ 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */,
+ 8E3A1F080FAA199F009B0518 /* cover320x416.png */,
+ 32CA4F630368D1EE00C91783 /* HelloWorld_Prefix.pch */,
+ 8D1107310486CEB800E47090 /* Info.plist */,
+ 8E4156E80FA4EE0E0006D27C /* icon.png */,
+ 8E4156E70FA4EE0E0006D27C /* Default.png */,
+ );
+ name = Support;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 1D6058900D05DD3D006BFB54 /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ 1D60588D0D05DD3D006BFB54 /* Resources */,
+ 1D60588E0D05DD3D006BFB54 /* Sources */,
+ 1D60588F0D05DD3D006BFB54 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = HelloWorld;
+ productReference = 1D6058910D05DD3D006BFB54 /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 1D6058900D05DD3D006BFB54 /* HelloWorld */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 1D60588D0D05DD3D006BFB54 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8E4156E90FA4EE0E0006D27C /* Default.png in Resources */,
+ 8E4156EA0FA4EE0E0006D27C /* icon.png in Resources */,
+ 8E3A1F090FAA199F009B0518 /* cover320x416.png in Resources */,
+ 8E785FCB0FCDB853006EA81F /* TestBedViewController.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 1D60588E0D05DD3D006BFB54 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1D60589B0D05DD56006BFB54 /* main.m in Sources */,
+ 8EFD3CAD10518F16007BACA7 /* UIDevice-Reachability.m in Sources */,
+ 8EFD3D5A1051977F007BACA7 /* ModalAlert.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1D6058940D05DD3E006BFB54 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Erica Sadun";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks\"",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = HelloWorld_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ PREBINDING = NO;
+ PRODUCT_NAME = HelloWorld;
+ };
+ name = Debug;
+ };
+ 1D6058950D05DD3E006BFB54 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks\"",
+ );
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = HelloWorld_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ PREBINDING = NO;
+ PRODUCT_NAME = HelloWorld;
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+ C01FCF4F08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CODE_SIGN_IDENTITY = "Erica Sadun";
+ "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ PRODUCT_NAME = "Oh Hello";
+ SDKROOT = iphoneos2.0;
+ };
+ name = Debug;
+ };
+ C01FCF5008A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ PREBINDING = NO;
+ SDKROOT = iphoneos2.0;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1D6058940D05DD3E006BFB54 /* Debug */,
+ 1D6058950D05DD3E006BFB54 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4F08A954540054247B /* Debug */,
+ C01FCF5008A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
View
8 C20-StoreKit/02-Purchase/HelloWorld_Prefix.pch
@@ -0,0 +1,8 @@
+//
+// Prefix header for all source files of the 'HelloWorld' target in the 'HelloWorld' project
+//
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+ #import <UIKit/UIKit.h>
+#endif
View
26 C20-StoreKit/02-Purchase/Info.plist
@@ -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>CFBundleDisplayName</key>
+ <string>StoreKitDemo</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.sadun.Scanner</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
View
15 C20-StoreKit/02-Purchase/ModalAlert.h
@@ -0,0 +1,15 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface ModalAlert : NSObject
++ (NSString *) ask: (NSString *) question withTextPrompt: (NSString *) prompt;
++ (NSUInteger) ask: (NSString *) question withCancel: (NSString *) cancelButtonTitle withButtons: (NSArray *) buttons;
++ (void) say: (id)formatstring,...;
++ (BOOL) ask: (id)formatstring,...;
++ (BOOL) confirm: (id)formatstring,...;
+@end
View
180 C20-StoreKit/02-Purchase/ModalAlert.m
@@ -0,0 +1,180 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+/*
+ Thanks to Kevin Ballard for suggesting the UITextField as subview approach
+ All credit to Kenny TM. Mistakes are mine.
+ To Do: Ensure that only one runs at a time -- is that possible?
+ */
+
+#import "ModalAlert.h"
+#import <stdarg.h>
+
+#define TEXT_FIELD_TAG 9999
+
+@interface ModalAlertDelegate : NSObject <UIAlertViewDelegate, UITextFieldDelegate>
+{
+ CFRunLoopRef currentLoop;
+ NSString *text;
+ NSUInteger index;
+}
+@property (assign) NSUInteger index;
+@property (retain) NSString *text;
+@end
+
+@implementation ModalAlertDelegate
+@synthesize index;
+@synthesize text;
+
+-(id) initWithRunLoop: (CFRunLoopRef)runLoop
+{
+ if (self = [super init]) currentLoop = runLoop;
+ return self;
+}
+
+// User pressed button. Retrieve results
+-(void)alertView:(UIAlertView*)aView clickedButtonAtIndex:(NSInteger)anIndex
+{
+ UITextField *tf = (UITextField *)[aView viewWithTag:TEXT_FIELD_TAG];
+ if (tf) self.text = tf.text;
+ self.index = anIndex;
+ CFRunLoopStop(currentLoop);
+}
+
+- (BOOL) isLandscape
+{
+ return ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft) || ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight);
+}
+
+// Move alert into place to allow keyboard to appear
+- (void) moveAlert: (UIAlertView *) alertView
+{
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ [UIView beginAnimations:nil context:context];
+ [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
+ [UIView setAnimationDuration:0.25f];
+ if (![self isLandscape])
+ alertView.center = CGPointMake(160.0f, 180.0f);
+ else
+ alertView.center = CGPointMake(240.0f, 90.0f);
+ [UIView commitAnimations];
+
+ [[alertView viewWithTag:TEXT_FIELD_TAG] becomeFirstResponder];
+}
+
+- (void) dealloc
+{
+ self.text = nil;
+ [super dealloc];
+}
+
+@end
+
+@implementation ModalAlert
+
++ (NSUInteger) ask: (NSString *) question withCancel: (NSString *) cancelButtonTitle withButtons: (NSArray *) buttons
+{
+ CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
+
+ // Create Alert
+ ModalAlertDelegate *madelegate = [[ModalAlertDelegate alloc] initWithRunLoop:currentLoop];
+ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:question message:nil delegate:madelegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
+ for (NSString *buttonTitle in buttons) [alertView addButtonWithTitle:buttonTitle];
+ [alertView show];
+
+ // Wait for response
+ CFRunLoopRun();
+
+ // Retrieve answer
+ NSUInteger answer = madelegate.index;
+ [alertView release];
+ [madelegate release];
+ return answer;
+}
+
++ (void) say: (id)formatstring,...
+{
+ va_list arglist;
+ va_start(arglist, formatstring);
+ id statement = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
+ va_end(arglist);
+ [ModalAlert ask:statement withCancel:@"Okay" withButtons:nil];
+ [statement release];
+}
+
++ (BOOL) ask: (id)formatstring,...
+{
+ va_list arglist;
+ va_start(arglist, formatstring);
+ id statement = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
+ va_end(arglist);
+ BOOL answer = ([ModalAlert ask:statement withCancel:nil withButtons:[NSArray arrayWithObjects:@"Yes", @"No", nil]] == 0);
+ [statement release];
+ return answer;
+}
+
++ (BOOL) confirm: (id)formatstring,...
+{
+ va_list arglist;
+ va_start(arglist, formatstring);
+ id statement = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
+ va_end(arglist);
+ BOOL answer = [ModalAlert ask:statement withCancel:@"Cancel" withButtons:[NSArray arrayWithObject:@"OK"]];
+ [statement release];
+ return answer;
+}
+
++(NSString *) textQueryWith: (NSString *)question prompt: (NSString *)prompt button1: (NSString *)button1 button2:(NSString *) button2
+{
+ // Create alert
+ CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
+ ModalAlertDelegate *madelegate = [[ModalAlertDelegate alloc] initWithRunLoop:currentLoop];
+ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:question message:@"\n" delegate:madelegate cancelButtonTitle:button1 otherButtonTitles:button2, nil];
+
+ // Build text field
+ UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 260.0f, 30.0f)];
+ tf.borderStyle = UITextBorderStyleRoundedRect;
+ tf.tag = TEXT_FIELD_TAG;
+ tf.placeholder = prompt;
+ tf.clearButtonMode = UITextFieldViewModeWhileEditing;
+ tf.keyboardType = UIKeyboardTypeAlphabet;
+ tf.keyboardAppearance = UIKeyboardAppearanceAlert;
+ tf.autocapitalizationType = UITextAutocapitalizationTypeWords;
+ tf.autocorrectionType = UITextAutocorrectionTypeNo;
+ tf.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
+
+ // Show alert and wait for it to finish displaying
+ [alertView show];
+ while (CGRectEqualToRect(alertView.bounds, CGRectZero));
+
+ // Find the center for the text field and add it
+ CGRect bounds = alertView.bounds;
+ tf.center = CGPointMake(bounds.size.width / 2.0f, bounds.size.height / 2.0f - 10.0f);
+ [alertView addSubview:tf];
+ [tf release];
+
+ // Set the field to first responder and move it into place
+ [madelegate performSelector:@selector(moveAlert:) withObject:alertView afterDelay: 0.7f];
+
+ // Start the run loop
+ CFRunLoopRun();
+
+ // Retrieve the user choices
+ NSUInteger index = madelegate.index;
+ NSString *answer = [[madelegate.text copy] autorelease];
+ if (index == 0) answer = nil; // assumes cancel in position 0
+
+ [alertView release];
+ [madelegate release];
+ return answer;
+}
+
++ (NSString *) ask: (NSString *) question withTextPrompt: (NSString *) prompt
+{
+ return [ModalAlert textQueryWith:question prompt:prompt button1:@"Cancel" button2:@"OK"];
+}
+@end
+
View
223 C20-StoreKit/02-Purchase/TestBedViewController.xib
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.03">
+ <data>
+ <int key="IBDocument.SystemTarget">768</int>
+ <string key="IBDocument.SystemVersion">9J61</string>
+ <string key="IBDocument.InterfaceBuilderVersion">680</string>
+ <string key="IBDocument.AppKitVersion">949.46</string>
+ <string key="IBDocument.HIToolboxVersion">353.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="35"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="372490531">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ </object>
+ <object class="IBProxyObject" id="843779117">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ </object>
+ <object class="IBUIView" id="440620744">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">292</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIImageView" id="1064941195">
+ <reference key="NSNextResponder" ref="440620744"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{320, 416}</string>
+ <reference key="NSSuperview" ref="440620744"/>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <int key="IBUIContentMode">4</int>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <object class="NSCustomResource" key="IBUIImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">cover320x416.png</string>
+ </object>
+ </object>
+ <object class="IBUITextView" id="311618606">
+ <reference key="NSNextResponder" ref="440620744"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrameSize">{320, 279}</string>
+ <reference key="NSSuperview" ref="440620744"/>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <bool key="IBUIShowsHorizontalScrollIndicator">NO</bool>
+ <bool key="IBUIDelaysContentTouches">NO</bool>
+ <bool key="IBUICanCancelContentTouches">NO</bool>
+ <bool key="IBUIBouncesZoom">NO</bool>
+ <bool key="IBUIEditable">NO</bool>
+ <string key="IBUIText"/>
+ <object class="IBUITextInputTraits" key="IBUITextInputTraits">
+ <int key="IBUIAutocapitalizationType">2</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{320, 416}</string>
+ <reference key="NSSuperview"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ <object class="NSColorSpace" key="NSCustomColorSpace">
+ <int key="NSID">2</int>
+ </object>
+ </object>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+ <object class="IBUISimulatedNavigationBarMetrics" key="IBUISimulatedTopBarMetrics">
+ <bool key="IBUIPrompted">NO</bool>
+ </object>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">view</string>
+ <reference key="source" ref="372490531"/>
+ <reference key="destination" ref="440620744"/>
+ </object>
+ <int key="connectionID">33</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">textView</string>
+ <reference key="source" ref="372490531"/>
+ <reference key="destination" ref="311618606"/>
+ </object>
+ <int key="connectionID">36</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="884947135">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="372490531"/>
+ <reference key="parent" ref="884947135"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="843779117"/>
+ <reference key="parent" ref="884947135"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">32</int>
+ <reference key="object" ref="440620744"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1064941195"/>
+ <reference ref="311618606"/>
+ </object>
+ <reference key="parent" ref="884947135"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">34</int>
+ <reference key="object" ref="1064941195"/>
+ <reference key="parent" ref="440620744"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">35</int>
+ <reference key="object" ref="311618606"/>
+ <reference key="parent" ref="440620744"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.CustomClassName</string>
+ <string>-2.CustomClassName</string>
+ <string>32.IBEditorWindowLastContentRect</string>
+ <string>32.IBPluginDependency</string>
+ <string>35.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>TestBedViewController</string>
+ <string>UIResponder</string>
+ <string>{{21, 492}, {320, 480}}</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">36</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">TestBedViewController</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>textView</string>
+ <string>view</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UITextView</string>
+ <string>UIView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">HelloWorld.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <string key="IBCocoaTouchPluginVersion">3.1</string>
+ </data>
+</archive>
View
33 C20-StoreKit/02-Purchase/UIDevice-Reachability.h
@@ -0,0 +1,33 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License for anything not specifically marked as developed by a third party.
+ Apple's code excluded.
+ Use at your own risk
+ */
+
+#import <UIKit/UIKit.h>
+
+@protocol ReachabilityWatcher <NSObject>
+- (void) reachabilityChanged;
+@end
+
+@interface UIDevice (Reachability)
++ (NSString *) stringFromAddress: (const struct sockaddr *) address;
++ (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address;
+
++ (NSString *) hostname;
++ (NSString *) getIPAddressForHost: (NSString *) theHost;
++ (NSString *) localIPAddress;
++ (NSString *) localWiFiIPAddress;
++ (NSString *) whatismyipdotcom;
+
++ (BOOL) hostAvailable: (NSString *) theHost;
++ (BOOL) networkAvailable;
++ (BOOL) activeWLAN;
++ (BOOL) activeWWAN;
++ (BOOL) performWiFiCheck;
+
++ (BOOL) scheduleReachabilityWatcher: (id) watcher;
++ (void) unscheduleReachabilityWatcher;
+@end
View
273 C20-StoreKit/02-Purchase/UIDevice-Reachability.m
@@ -0,0 +1,273 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License for anything not specifically marked as developed by a third party.
+ Apple's code excluded.
+ Use at your own risk
+ */
+
+#import <SystemConfiguration/SystemConfiguration.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#import <dlfcn.h>
+#import "UIDevice-Reachability.h"
+
+@implementation UIDevice (Reachability)
+SCNetworkConnectionFlags connectionFlags;
+SCNetworkReachabilityRef reachability;
+
+#pragma mark Class IP and Host Utilities
+// This IP Utilities are mostly inspired by or derived from Apple code. Thank you Apple.
+
++ (NSString *) stringFromAddress: (const struct sockaddr *) address
+{
+ if(address && address->sa_family == AF_INET) {
+ const struct sockaddr_in* sin = (struct sockaddr_in*) address;
+ return [NSString stringWithFormat:@"%@:%d", [NSString stringWithUTF8String:inet_ntoa(sin->sin_addr)], ntohs(sin->sin_port)];
+ }
+
+ return nil;
+}
+
++ (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
+{
+ if (!IPAddress || ![IPAddress length]) {
+ return NO;
+ }
+
+ memset((char *) address, sizeof(struct sockaddr_in), 0);
+ address->sin_family = AF_INET;
+ address->sin_len = sizeof(struct sockaddr_in);
+
+ int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
+ if (conversionResult == 0) {
+ NSAssert1(conversionResult != 1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
+ return NO;
+ }
+
+ return YES;
+}
+
++ (NSString *) hostname
+{
+ char baseHostName[255];
+ int success = gethostname(baseHostName, 255);
+ if (success != 0) return nil;
+ baseHostName[255] = '\0';
+
+ #if !TARGET_IPHONE_SIMULATOR
+ return [NSString stringWithFormat:@"%s.local", baseHostName];
+ #else
+ return [NSString stringWithFormat:@"%s", baseHostName];
+ #endif
+}
+
++ (NSString *) getIPAddressForHost: (NSString *) theHost
+{
+ struct hostent *host = gethostbyname([theHost UTF8String]);
+ if (!host) {herror("resolv"); return NULL; }
+ struct in_addr **list = (struct in_addr **)host->h_addr_list;
+ NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0]) encoding:NSUTF8StringEncoding];
+ return addressString;
+}
+
++ (NSString *) localIPAddress
+{
+ struct hostent *host = gethostbyname([[self hostname] UTF8String]);
+ if (!host) {herror("resolv"); return nil;}
+ struct in_addr **list = (struct in_addr **)host->h_addr_list;
+ return [NSString stringWithCString:inet_ntoa(*list[0]) encoding:NSUTF8StringEncoding];
+}
+
+// Matt Brown's get WiFi IP addy solution
+// Author gave permission to use in Cookbook under cookbook license
+// http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html
++ (NSString *) localWiFiIPAddress
+{
+ BOOL success;
+ struct ifaddrs * addrs;
+ const struct ifaddrs * cursor;
+
+ success = getifaddrs(&addrs) == 0;
+ if (success) {
+ cursor = addrs;
+ while (cursor != NULL) {
+ // the second test keeps from picking up the loopback address
+ if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0)
+ {
+ NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
+ if ([name isEqualToString:@"en0"]) // Wi-Fi adapter
+ return [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
+ }
+ cursor = cursor->ifa_next;
+ }
+ freeifaddrs(addrs);
+ }
+ return nil;
+}
+
++ (NSString *) whatismyipdotcom
+{
+ NSError *error;
+ NSURL *ipURL = [NSURL URLWithString:@"http://www.whatismyip.com/automation/n09230945.asp"];
+ NSString *ip = [NSString stringWithContentsOfURL:ipURL encoding:1 error:&error];
+ return ip ? ip : [error localizedDescription];
+}
+
++ (BOOL) hostAvailable: (NSString *) theHost
+{
+
+ NSString *addressString = [self getIPAddressForHost:theHost];
+ if (!addressString)
+ {
+ printf("Error recovering IP address from host name\n");
+ return NO;
+ }
+
+ struct sockaddr_in address;
+ BOOL gotAddress = [self addressFromString:addressString address:&address];
+
+ if (!gotAddress)
+ {
+ printf("Error recovering sockaddr address from %s\n", [addressString UTF8String]);
+ return NO;
+ }
+
+ SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&address);
+ SCNetworkReachabilityFlags flags;
+
+ BOOL didRetrieveFlags =SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
+ CFRelease(defaultRouteReachability);
+
+ if (!didRetrieveFlags)
+ {
+ printf("Error. Could not recover network reachability flags\n");
+ return NO;
+ }
+
+ BOOL isReachable = flags & kSCNetworkFlagsReachable;
+ return isReachable ? YES : NO;;
+}
+
+#pragma mark Checking Connections
+
++ (void) pingReachabilityInternal
+{
+ if (!reachability)
+ {
+ BOOL ignoresAdHocWiFi = NO;
+ struct sockaddr_in ipAddress;
+ bzero(&ipAddress, sizeof(ipAddress));
+ ipAddress.sin_len = sizeof(ipAddress);
+ ipAddress.sin_family = AF_INET;
+ ipAddress.sin_addr.s_addr = htonl(ignoresAdHocWiFi ? INADDR_ANY : IN_LINKLOCALNETNUM);
+
+ /* Can also create zero addy
+ struct sockaddr_in zeroAddress;
+ bzero(&zeroAddress, sizeof(zeroAddress));
+ zeroAddress.sin_len = sizeof(zeroAddress);
+ zeroAddress.sin_family = AF_INET; */
+
+ reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&ipAddress);
+ CFRetain(reachability);
+ }
+
+ // Recover reachability flags
+ BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(reachability, &connectionFlags);
+ if (!didRetrieveFlags) printf("Error. Could not recover network reachability flags\n");
+}
+
++ (BOOL) networkAvailable
+{
+ [self pingReachabilityInternal];
+ BOOL isReachable = ((connectionFlags & kSCNetworkFlagsReachable) != 0);
+ BOOL needsConnection = ((connectionFlags & kSCNetworkFlagsConnectionRequired) != 0);
+ return (isReachable && !needsConnection) ? YES : NO;
+}
+
++ (BOOL) activeWWAN
+{
+ if (![self networkAvailable]) return NO;
+ return ((connectionFlags & kSCNetworkReachabilityFlagsIsWWAN) != 0);
+}
+
++ (BOOL) activeWLAN
+{
+ return ([UIDevice localWiFiIPAddress] != nil);
+}
+
+
+#pragma mark WiFi Check and Alert
++ (void) showAlert: (id) formatstring,...
+{
+ va_list arglist;
+ if (!formatstring) return;
+ va_start(arglist, formatstring);
+ id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];
+ va_end(arglist);
+
+ UIAlertView *av = [[[UIAlertView alloc] initWithTitle:outstring message:nil delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];
+ [av show];
+}
+
++ (BOOL) performWiFiCheck
+{
+ if (![self networkAvailable] || ![self activeWLAN])
+ {
+ [self performSelector:@selector(showAlert:) withObject:@"This application requires WiFi. Please enable WiFi in Settings and run this application again." afterDelay:0.5f];
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark Monitoring reachability
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* info)
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ [(id)info performSelector:@selector(reachabilityChanged)];
+ [pool release];
+}
+
++ (BOOL) scheduleReachabilityWatcher: (id) watcher
+{
+ if (![watcher conformsToProtocol:@protocol(ReachabilityWatcher)])
+ {
+ NSLog(@"Watcher must conform to ReachabilityWatcher protocol. Cannot continue.");
+ return NO;
+ }
+
+ [self pingReachabilityInternal];
+
+ SCNetworkReachabilityContext context = {0, watcher, NULL, NULL, NULL};
+ if(SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context))
+ {
+ if(!SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes))
+ {
+ NSLog(@"Error: Could not schedule reachability");
+ SCNetworkReachabilitySetCallback(reachability, NULL, NULL);
+ return NO;
+ }
+ }
+ else
+ {
+ NSLog(@"Error: Could not set reachability callback");
+ return NO;
+ }
+
+ return YES;
+}
+
++ (void) unscheduleReachabilityWatcher
+{
+ SCNetworkReachabilitySetCallback(reachability, NULL, NULL);
+ if (SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes))
+ NSLog(@"Unscheduled reachability");
+ else
+ NSLog(@"Error: Could not unschedule reachability");
+
+ CFRelease(reachability);
+ reachability = nil;
+}
+@end
View
BIN C20-StoreKit/02-Purchase/cover320x416.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN C20-StoreKit/02-Purchase/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
180 C20-StoreKit/02-Purchase/main.m
@@ -0,0 +1,180 @@
+/*
+ Erica Sadun, http://ericasadun.com
+ iPhone Developer's Cookbook, 3.0 Edition
+ BSD License, Use at your own risk
+ */
+
+#import <UIKit/UIKit.h>
+#import <StoreKit/StoreKit.h>
+#import "UIDevice-Reachability.h"
+#import "ModalAlert.h"
+
+#define COOKBOOK_PURPLE_COLOR [UIColor colorWithRed:0.20392f green:0.19607f blue:0.61176f alpha:1.0f]
+#define BARBUTTON(TITLE, SELECTOR) [[[UIBarButtonItem alloc] initWithTitle:TITLE style:UIBarButtonItemStylePlain target:self action:SELECTOR] autorelease]
+
+#define PRODUCT_ID @"com.sadun.scanner.disclosure2"
+#define SANDBOX YES
+
+@interface TestBedViewController : UIViewController <SKProductsRequestDelegate, SKPaymentTransactionObserver>
+{
+ NSMutableString *log;
+ IBOutlet UITextView *textView;
+}
+@property (retain) NSMutableString *log;
+@property (retain) UITextView *textView;
+@end
+
+@implementation TestBedViewController
+@synthesize log;
+@synthesize textView;
+
+- (void) doLog: (NSString *) formatstring, ...
+{
+ va_list arglist;
+ if (!formatstring) return;
+ va_start(arglist, formatstring);
+ NSString *outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];
+ va_end(arglist);
+ [self.log appendString:outstring];
+ [self.log appendString:@"\n"];
+ self.textView.text = self.log;
+}
+
+- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
+{
+ [self doLog:@"Error: Could not contact App Store properly, %@", [error localizedDescription]];
+}
+
+- (void)requestDidFinish:(SKRequest *)request
+{
+ // Release the request
+ [request release];
+ [self doLog:@"Request finished."];
+}
+
+- (void) repurchase
+{
+ [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
+}
+
+- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
+{
+ SKProduct *product = [[response products] lastObject];
+ if (!product)
+ {
+ [self doLog:@"Error retrieving product information from App Store. Sorry! Please try again later."];
+ return;
+ }
+
+ // Retrieve the localized price
+ NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
+ [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
+ [numberFormatter setLocale:product.priceLocale];
+ NSString *formattedString = [numberFormatter stringFromNumber:product.price];
+ [numberFormatter release];
+
+ // Create a description that gives a heads up about
+ // a non-consumable purchase
+ NSString *buyString = formattedString;
+ NSString *describeString = [NSString stringWithFormat:@"%@\n\nIf you have already purchased this item, you will not be charged again.", product.localizedDescription];
+ NSArray *buttons = [NSArray arrayWithObject: buyString];
+
+ // Offer the user a choice to buy or not buy
+ if ([ModalAlert ask:describeString withCancel:@"No Thanks" withButtons:buttons])
+ {
+ // Purchase the item
+ SKPayment *payment = [SKPayment paymentWithProductIdentifier:PRODUCT_ID];
+ [[SKPaymentQueue defaultQueue] addPayment:payment];
+ }
+ else
+ {
+ // restore the GUI to provide a buy/purchase button
+ // or otherwise to a ready-to-buy state
+ }
+}
+
+#pragma mark payments
+- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
+{
+}
+
+- (void) completedPurchaseTransaction: (SKPaymentTransaction *) transaction
+{
+ // PERFORM THE SUCCESS ACTION THAT UNLOCKS THE FEATURE HERE
+
+ // Finish transaction
+ [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
+ [ModalAlert say:@"Thank you for your purchase."];
+}
+
+- (void) handleFailedTransaction: (SKPaymentTransaction *) transaction
+{
+ if (transaction.error.code != SKErrorPaymentCancelled)
+ {
+ [ModalAlert say:@"Transaction Error. Please try again later."];
+ [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
+ }
+}
+
+- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
+{
+ for (SKPaymentTransaction *transaction in transactions) {
+ switch (transaction.transactionState) {
+ case SKPaymentTransactionStatePurchased:
+ case SKPaymentTransactionStateRestored:
+ [self completedPurchaseTransaction:transaction];
+ break;
+ case SKPaymentTransactionStateFailed:
+ [self handleFailedTransaction:transaction];
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+- (void) action: (UIBarButtonItem *) bbi
+{
+ // Init log
+ self.log = [NSMutableString string];
+ [self doLog:@"Submitting Request... Please wait."];
+
+ // Create the product request and start it
+ SKProductsRequest *preq = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:PRODUCT_ID]];
+ preq.delegate = self;
+ [preq start];
+}
+
+- (void) viewDidLoad
+{
+ self.navigationController.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
+ self.navigationItem.rightBarButtonItem = BARBUTTON(@"Action", @selector(action:));
+
+ self.log = [NSMutableString string];
+ if (![UIDevice networkAvailable])
+ [self doLog:@"You are not connected to the network! All StoreKit calls will fail!"];
+}
+@end
+
+@interface TestBedAppDelegate : NSObject <UIApplicationDelegate>
+@end
+
+@implementation TestBedAppDelegate
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+ UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ TestBedViewController *tbvc = [[TestBedViewController alloc] init];
+ UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:tbvc];
+ [[SKPaymentQueue defaultQueue] addTransactionObserver:tbvc];
+ [window addSubview:nav.view];
+ [window makeKeyAndVisible];
+}
+@end
+
+int main(int argc, char *argv[])
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int retVal = UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
+ [pool release];
+ return retVal;
+}
View
BIN C20-StoreKit/03-Validating Receipt/Default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
269 C20-StoreKit/03-Validating Receipt/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,269 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; };
+ 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
+ 8E3A1F090FAA199F009B0518 /* cover320x416.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E3A1F080FAA199F009B0518 /* cover320x416.png */; };
+ 8E4156E90FA4EE0E0006D27C /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E70FA4EE0E0006D27C /* Default.png */; };
+ 8E4156EA0FA4EE0E0006D27C /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8E4156E80FA4EE0E0006D27C /* icon.png */; };
+ 8E785FCB0FCDB853006EA81F /* TestBedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */; };
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */; };
+ 8EFD3CAD10518F16007BACA7 /* UIDevice-Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */; };
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */; };
+ 8EFD3D5A1051977F007BACA7 /* ModalAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3D591051977F007BACA7 /* ModalAlert.m */; };
+ 8EFD3D9C10519F84007BACA7 /* NSData-Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFD3D9B10519F84007BACA7 /* NSData-Base64.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 32CA4F630368D1EE00C91783 /* HelloWorld_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelloWorld_Prefix.pch; sourceTree = "<group>"; };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 8E3A1F080FAA199F009B0518 /* cover320x416.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cover320x416.png; sourceTree = "<group>"; };
+ 8E4156E70FA4EE0E0006D27C /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
+ 8E4156E80FA4EE0E0006D27C /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
+ 8E785FCA0FCDB853006EA81F /* TestBedViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TestBedViewController.xib; sourceTree = "<group>"; };
+ 8EFD3C7B10518CF4007BACA7 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ 8EFD3CAB10518F16007BACA7 /* UIDevice-Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice-Reachability.h"; sourceTree = "<group>"; };
+ 8EFD3CAC10518F16007BACA7 /* UIDevice-Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice-Reachability.m"; sourceTree = "<group>"; };
+ 8EFD3D0A1051917D007BACA7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = "../../../00SampleCodeWork/ZZ-TextOutputApp/iphoneos2.0/System/Library/Frameworks/SystemConfiguration.framework"; sourceTree = SOURCE_ROOT; };
+ 8EFD3D581051977F007BACA7 /* ModalAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalAlert.h; sourceTree = "<group>"; };
+ 8EFD3D591051977F007BACA7 /* ModalAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalAlert.m; sourceTree = "<group>"; };
+ 8EFD3D9A10519F84007BACA7 /* NSData-Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData-Base64.h"; sourceTree = "<group>"; };
+ 8EFD3D9B10519F84007BACA7 /* NSData-Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData-Base64.m"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1D60588F0D05DD3D006BFB54 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
+ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
+ 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */,
+ 8EFD3C7C10518CF4007BACA7 /* StoreKit.framework in Frameworks */,
+ 8EFD3D0B1051917D007BACA7 /* SystemConfiguration.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 1D6058910D05DD3D006BFB54 /* HelloWorld.app */,