Initial commit of running code.
This commit is contained in:
Родитель
86b6a0b62c
Коммит
56d03b73cf
|
@ -0,0 +1,519 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5B03FAA618464C500001D1C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAA518464C500001D1C3 /* Foundation.framework */; };
|
||||
5B03FAA818464C500001D1C3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAA718464C500001D1C3 /* CoreGraphics.framework */; };
|
||||
5B03FAAA18464C500001D1C3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAA918464C500001D1C3 /* UIKit.framework */; };
|
||||
5B03FAB018464C500001D1C3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B03FAAE18464C500001D1C3 /* InfoPlist.strings */; };
|
||||
5B03FAB218464C500001D1C3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAB118464C500001D1C3 /* main.m */; };
|
||||
5B03FAB618464C500001D1C3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAB518464C500001D1C3 /* AppDelegate.m */; };
|
||||
5B03FAB918464C500001D1C3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B03FAB718464C500001D1C3 /* Main.storyboard */; };
|
||||
5B03FABC18464C500001D1C3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FABB18464C500001D1C3 /* ViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
5B03FABE18464C500001D1C3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5B03FABD18464C500001D1C3 /* Images.xcassets */; };
|
||||
5B03FAC518464C500001D1C3 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAC418464C500001D1C3 /* XCTest.framework */; };
|
||||
5B03FAC618464C500001D1C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAA518464C500001D1C3 /* Foundation.framework */; };
|
||||
5B03FAC718464C500001D1C3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAA918464C500001D1C3 /* UIKit.framework */; };
|
||||
5B03FACF18464C500001D1C3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B03FACD18464C500001D1C3 /* InfoPlist.strings */; };
|
||||
5B03FAD118464C500001D1C3 /* GoogleAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAD018464C500001D1C3 /* GoogleAuthTests.m */; };
|
||||
5B03FAF418464D260001D1C3 /* GTMHTTPFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAEC18464D260001D1C3 /* GTMHTTPFetcher.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
5B03FAF518464D260001D1C3 /* GTMOAuth2Authentication.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAEE18464D260001D1C3 /* GTMOAuth2Authentication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
5B03FAF618464D260001D1C3 /* GTMOAuth2SignIn.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAF018464D260001D1C3 /* GTMOAuth2SignIn.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
5B03FAF718464D260001D1C3 /* GTMOAuth2ViewControllerTouch.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B03FAF218464D260001D1C3 /* GTMOAuth2ViewControllerTouch.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
5B03FAF818464D260001D1C3 /* GTMOAuth2ViewTouch.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B03FAF318464D260001D1C3 /* GTMOAuth2ViewTouch.xib */; };
|
||||
5B03FAFA18464DFE0001D1C3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAF918464DFE0001D1C3 /* Security.framework */; };
|
||||
5B03FAFC18464E040001D1C3 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B03FAFB18464E040001D1C3 /* SystemConfiguration.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
5B03FAC818464C500001D1C3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5B03FA9A18464C500001D1C3 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 5B03FAA118464C500001D1C3;
|
||||
remoteInfo = GoogleAuth;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5B03FAA218464C500001D1C3 /* GoogleAuth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GoogleAuth.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5B03FAA518464C500001D1C3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
5B03FAA718464C500001D1C3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
5B03FAA918464C500001D1C3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
5B03FAAD18464C500001D1C3 /* GoogleAuth-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleAuth-Info.plist"; sourceTree = "<group>"; };
|
||||
5B03FAAF18464C500001D1C3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
5B03FAB118464C500001D1C3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
5B03FAB318464C500001D1C3 /* GoogleAuth-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GoogleAuth-Prefix.pch"; sourceTree = "<group>"; };
|
||||
5B03FAB418464C500001D1C3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
5B03FAB518464C500001D1C3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
5B03FAB818464C500001D1C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
5B03FABA18464C500001D1C3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
5B03FABB18464C500001D1C3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
5B03FABD18464C500001D1C3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
5B03FAC318464C500001D1C3 /* GoogleAuthTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GoogleAuthTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5B03FAC418464C500001D1C3 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||
5B03FACC18464C500001D1C3 /* GoogleAuthTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleAuthTests-Info.plist"; sourceTree = "<group>"; };
|
||||
5B03FACE18464C500001D1C3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
5B03FAD018464C500001D1C3 /* GoogleAuthTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleAuthTests.m; sourceTree = "<group>"; };
|
||||
5B03FAEB18464D260001D1C3 /* GTMHTTPFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMHTTPFetcher.h; sourceTree = "<group>"; };
|
||||
5B03FAEC18464D260001D1C3 /* GTMHTTPFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMHTTPFetcher.m; sourceTree = "<group>"; };
|
||||
5B03FAED18464D260001D1C3 /* GTMOAuth2Authentication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMOAuth2Authentication.h; sourceTree = "<group>"; };
|
||||
5B03FAEE18464D260001D1C3 /* GTMOAuth2Authentication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMOAuth2Authentication.m; sourceTree = "<group>"; };
|
||||
5B03FAEF18464D260001D1C3 /* GTMOAuth2SignIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMOAuth2SignIn.h; sourceTree = "<group>"; };
|
||||
5B03FAF018464D260001D1C3 /* GTMOAuth2SignIn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMOAuth2SignIn.m; sourceTree = "<group>"; };
|
||||
5B03FAF118464D260001D1C3 /* GTMOAuth2ViewControllerTouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMOAuth2ViewControllerTouch.h; sourceTree = "<group>"; };
|
||||
5B03FAF218464D260001D1C3 /* GTMOAuth2ViewControllerTouch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMOAuth2ViewControllerTouch.m; sourceTree = "<group>"; };
|
||||
5B03FAF318464D260001D1C3 /* GTMOAuth2ViewTouch.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GTMOAuth2ViewTouch.xib; sourceTree = "<group>"; };
|
||||
5B03FAF918464DFE0001D1C3 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
5B03FAFB18464E040001D1C3 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
5B03FA9F18464C500001D1C3 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FAFC18464E040001D1C3 /* SystemConfiguration.framework in Frameworks */,
|
||||
5B03FAFA18464DFE0001D1C3 /* Security.framework in Frameworks */,
|
||||
5B03FAA818464C500001D1C3 /* CoreGraphics.framework in Frameworks */,
|
||||
5B03FAAA18464C500001D1C3 /* UIKit.framework in Frameworks */,
|
||||
5B03FAA618464C500001D1C3 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5B03FAC018464C500001D1C3 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FAC518464C500001D1C3 /* XCTest.framework in Frameworks */,
|
||||
5B03FAC718464C500001D1C3 /* UIKit.framework in Frameworks */,
|
||||
5B03FAC618464C500001D1C3 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
5B03FA9918464C500001D1C3 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAAB18464C500001D1C3 /* GoogleAuth */,
|
||||
5B03FACA18464C500001D1C3 /* GoogleAuthTests */,
|
||||
5B03FAA418464C500001D1C3 /* Frameworks */,
|
||||
5B03FAA318464C500001D1C3 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAA318464C500001D1C3 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAA218464C500001D1C3 /* GoogleAuth.app */,
|
||||
5B03FAC318464C500001D1C3 /* GoogleAuthTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAA418464C500001D1C3 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAFB18464E040001D1C3 /* SystemConfiguration.framework */,
|
||||
5B03FAF918464DFE0001D1C3 /* Security.framework */,
|
||||
5B03FAA518464C500001D1C3 /* Foundation.framework */,
|
||||
5B03FAA718464C500001D1C3 /* CoreGraphics.framework */,
|
||||
5B03FAA918464C500001D1C3 /* UIKit.framework */,
|
||||
5B03FAC418464C500001D1C3 /* XCTest.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAAB18464C500001D1C3 /* GoogleAuth */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAEA18464D260001D1C3 /* OAuth */,
|
||||
5B03FAB418464C500001D1C3 /* AppDelegate.h */,
|
||||
5B03FAB518464C500001D1C3 /* AppDelegate.m */,
|
||||
5B03FAB718464C500001D1C3 /* Main.storyboard */,
|
||||
5B03FABA18464C500001D1C3 /* ViewController.h */,
|
||||
5B03FABB18464C500001D1C3 /* ViewController.m */,
|
||||
5B03FABD18464C500001D1C3 /* Images.xcassets */,
|
||||
5B03FAAC18464C500001D1C3 /* Supporting Files */,
|
||||
);
|
||||
path = GoogleAuth;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAAC18464C500001D1C3 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAAD18464C500001D1C3 /* GoogleAuth-Info.plist */,
|
||||
5B03FAAE18464C500001D1C3 /* InfoPlist.strings */,
|
||||
5B03FAB118464C500001D1C3 /* main.m */,
|
||||
5B03FAB318464C500001D1C3 /* GoogleAuth-Prefix.pch */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FACA18464C500001D1C3 /* GoogleAuthTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAD018464C500001D1C3 /* GoogleAuthTests.m */,
|
||||
5B03FACB18464C500001D1C3 /* Supporting Files */,
|
||||
);
|
||||
path = GoogleAuthTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FACB18464C500001D1C3 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FACC18464C500001D1C3 /* GoogleAuthTests-Info.plist */,
|
||||
5B03FACD18464C500001D1C3 /* InfoPlist.strings */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAEA18464D260001D1C3 /* OAuth */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B03FAEB18464D260001D1C3 /* GTMHTTPFetcher.h */,
|
||||
5B03FAEC18464D260001D1C3 /* GTMHTTPFetcher.m */,
|
||||
5B03FAED18464D260001D1C3 /* GTMOAuth2Authentication.h */,
|
||||
5B03FAEE18464D260001D1C3 /* GTMOAuth2Authentication.m */,
|
||||
5B03FAEF18464D260001D1C3 /* GTMOAuth2SignIn.h */,
|
||||
5B03FAF018464D260001D1C3 /* GTMOAuth2SignIn.m */,
|
||||
5B03FAF118464D260001D1C3 /* GTMOAuth2ViewControllerTouch.h */,
|
||||
5B03FAF218464D260001D1C3 /* GTMOAuth2ViewControllerTouch.m */,
|
||||
5B03FAF318464D260001D1C3 /* GTMOAuth2ViewTouch.xib */,
|
||||
);
|
||||
path = OAuth;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
5B03FAA118464C500001D1C3 /* GoogleAuth */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5B03FAD418464C500001D1C3 /* Build configuration list for PBXNativeTarget "GoogleAuth" */;
|
||||
buildPhases = (
|
||||
5B03FA9E18464C500001D1C3 /* Sources */,
|
||||
5B03FA9F18464C500001D1C3 /* Frameworks */,
|
||||
5B03FAA018464C500001D1C3 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = GoogleAuth;
|
||||
productName = GoogleAuth;
|
||||
productReference = 5B03FAA218464C500001D1C3 /* GoogleAuth.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
5B03FAC218464C500001D1C3 /* GoogleAuthTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5B03FAD718464C500001D1C3 /* Build configuration list for PBXNativeTarget "GoogleAuthTests" */;
|
||||
buildPhases = (
|
||||
5B03FABF18464C500001D1C3 /* Sources */,
|
||||
5B03FAC018464C500001D1C3 /* Frameworks */,
|
||||
5B03FAC118464C500001D1C3 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5B03FAC918464C500001D1C3 /* PBXTargetDependency */,
|
||||
);
|
||||
name = GoogleAuthTests;
|
||||
productName = GoogleAuthTests;
|
||||
productReference = 5B03FAC318464C500001D1C3 /* GoogleAuthTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
5B03FA9A18464C500001D1C3 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0500;
|
||||
ORGANIZATIONNAME = "Wade Wegner";
|
||||
TargetAttributes = {
|
||||
5B03FAC218464C500001D1C3 = {
|
||||
TestTargetID = 5B03FAA118464C500001D1C3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 5B03FA9D18464C500001D1C3 /* Build configuration list for PBXProject "GoogleAuth" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 5B03FA9918464C500001D1C3;
|
||||
productRefGroup = 5B03FAA318464C500001D1C3 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
5B03FAA118464C500001D1C3 /* GoogleAuth */,
|
||||
5B03FAC218464C500001D1C3 /* GoogleAuthTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
5B03FAA018464C500001D1C3 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FAF818464D260001D1C3 /* GTMOAuth2ViewTouch.xib in Resources */,
|
||||
5B03FABE18464C500001D1C3 /* Images.xcassets in Resources */,
|
||||
5B03FAB018464C500001D1C3 /* InfoPlist.strings in Resources */,
|
||||
5B03FAB918464C500001D1C3 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5B03FAC118464C500001D1C3 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FACF18464C500001D1C3 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5B03FA9E18464C500001D1C3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FAF418464D260001D1C3 /* GTMHTTPFetcher.m in Sources */,
|
||||
5B03FAF618464D260001D1C3 /* GTMOAuth2SignIn.m in Sources */,
|
||||
5B03FABC18464C500001D1C3 /* ViewController.m in Sources */,
|
||||
5B03FAF518464D260001D1C3 /* GTMOAuth2Authentication.m in Sources */,
|
||||
5B03FAB618464C500001D1C3 /* AppDelegate.m in Sources */,
|
||||
5B03FAF718464D260001D1C3 /* GTMOAuth2ViewControllerTouch.m in Sources */,
|
||||
5B03FAB218464C500001D1C3 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5B03FABF18464C500001D1C3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B03FAD118464C500001D1C3 /* GoogleAuthTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
5B03FAC918464C500001D1C3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 5B03FAA118464C500001D1C3 /* GoogleAuth */;
|
||||
targetProxy = 5B03FAC818464C500001D1C3 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
5B03FAAE18464C500001D1C3 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5B03FAAF18464C500001D1C3 /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FAB718464C500001D1C3 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5B03FAB818464C500001D1C3 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B03FACD18464C500001D1C3 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5B03FACE18464C500001D1C3 /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
5B03FAD218464C500001D1C3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
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;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5B03FAD318464C500001D1C3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
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;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5B03FAD518464C500001D1C3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "GoogleAuth/GoogleAuth-Prefix.pch";
|
||||
INFOPLIST_FILE = "GoogleAuth/GoogleAuth-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5B03FAD618464C500001D1C3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "GoogleAuth/GoogleAuth-Prefix.pch";
|
||||
INFOPLIST_FILE = "GoogleAuth/GoogleAuth-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5B03FAD818464C500001D1C3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/GoogleAuth.app/GoogleAuth";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "GoogleAuth/GoogleAuth-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "GoogleAuthTests/GoogleAuthTests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5B03FAD918464C500001D1C3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/GoogleAuth.app/GoogleAuth";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "GoogleAuth/GoogleAuth-Prefix.pch";
|
||||
INFOPLIST_FILE = "GoogleAuthTests/GoogleAuthTests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
5B03FA9D18464C500001D1C3 /* Build configuration list for PBXProject "GoogleAuth" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5B03FAD218464C500001D1C3 /* Debug */,
|
||||
5B03FAD318464C500001D1C3 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5B03FAD418464C500001D1C3 /* Build configuration list for PBXNativeTarget "GoogleAuth" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5B03FAD518464C500001D1C3 /* Debug */,
|
||||
5B03FAD618464C500001D1C3 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
5B03FAD718464C500001D1C3 /* Build configuration list for PBXNativeTarget "GoogleAuthTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5B03FAD818464C500001D1C3 /* Debug */,
|
||||
5B03FAD918464C500001D1C3 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 5B03FA9A18464C500001D1C3 /* Project object */;
|
||||
}
|
7
src/GoogleAuth/GoogleAuth.xcodeproj/project.xcworkspace/contents.xcworkspacedata
сгенерированный
Normal file
7
src/GoogleAuth/GoogleAuth.xcodeproj/project.xcworkspace/contents.xcworkspacedata
сгенерированный
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:GoogleAuth.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// AppDelegate.h
|
||||
// GoogleAuth
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// AppDelegate.m
|
||||
// GoogleAuth
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
// Override point for customization after application launch.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="4514" systemVersion="12F45" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="Qf0-77-DD5">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="z8W-yX-Ua6">
|
||||
<objects>
|
||||
<navigationController definesPresentationContext="YES" id="Qf0-77-DD5" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="o1C-40-4HP">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="vXZ-lx-hvc" kind="relationship" relationship="rootViewController" id="xOs-kx-dQE"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="SSe-Dl-gGz" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-25" y="-148"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="ufC-wZ-h7g">
|
||||
<objects>
|
||||
<viewController id="vXZ-lx-hvc" customClass="ViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Gip-5b-NR5"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="YMB-fU-VNt"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="kh9-bI-dsS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" lineBreakMode="tailTruncation" numberOfLines="5" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="280" translatesAutoresizingMaskIntoConstraints="NO" id="4S5-uI-c8q">
|
||||
<rect key="frame" x="20" y="110" width="280" height="118"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="frU-MV-Qcb"/>
|
||||
<connections>
|
||||
<outlet property="TokenLabel" destination="4S5-uI-c8q" id="Wey-iq-gSi"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="467" y="-44"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
<simulatedScreenMetrics key="destination" type="retina4"/>
|
||||
</simulatedMetricsContainer>
|
||||
</document>
|
|
@ -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>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wadewegner.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Prefix header
|
||||
//
|
||||
// The contents of this file are implicitly included at the beginning of every source file.
|
||||
//
|
||||
|
||||
#import <Availability.h>
|
||||
|
||||
#ifndef __IPHONE_5_0
|
||||
#warning "This project uses features only available in iOS SDK 5.0 and later."
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
"extent" : "full-screen",
|
||||
"minimum-system-version" : "7.0",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "retina4",
|
||||
"extent" : "full-screen",
|
||||
"minimum-system-version" : "7.0",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,762 @@
|
|||
/* Copyright (c) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// GTMHTTPFetcher.h
|
||||
//
|
||||
|
||||
// This is essentially a wrapper around NSURLConnection for POSTs and GETs.
|
||||
// If setPostData: is called, then POST is assumed.
|
||||
//
|
||||
// When would you use this instead of NSURLConnection?
|
||||
//
|
||||
// - When you just want the result from a GET, POST, or PUT
|
||||
// - When you want the "standard" behavior for connections (redirection handling
|
||||
// an so on)
|
||||
// - When you want automatic retry on failures
|
||||
// - When you want to avoid cookie collisions with Safari and other applications
|
||||
// - When you are fetching resources with ETags and want to avoid the overhead
|
||||
// of repeated fetches of unchanged data
|
||||
// - When you need to set a credential for the http operation
|
||||
//
|
||||
// This is assumed to be a one-shot fetch request; don't reuse the object
|
||||
// for a second fetch.
|
||||
//
|
||||
// The fetcher may be created auto-released, in which case it will release
|
||||
// itself after the fetch completion callback. The fetcher is implicitly
|
||||
// retained as long as a connection is pending.
|
||||
//
|
||||
// But if you may need to cancel the fetcher, retain it and have the delegate
|
||||
// release the fetcher in the callbacks.
|
||||
//
|
||||
// Sample usage:
|
||||
//
|
||||
// NSURLRequest *request = [NSURLRequest requestWithURL:myURL];
|
||||
// GTMHTTPFetcher* myFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
|
||||
//
|
||||
// // optional upload body data
|
||||
// [myFetcher setPostData:[postString dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
//
|
||||
// [myFetcher beginFetchWithDelegate:self
|
||||
// didFinishSelector:@selector(myFetcher:finishedWithData:error:)];
|
||||
//
|
||||
// Upon fetch completion, the callback selector is invoked; it should have
|
||||
// this signature (you can use any callback method name you want so long as
|
||||
// the signature matches this):
|
||||
//
|
||||
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)retrievedData error:(NSError *)error;
|
||||
//
|
||||
// The block callback version looks like:
|
||||
//
|
||||
// [myFetcher beginFetchWithCompletionHandler:^(NSData *retrievedData, NSError *error) {
|
||||
// if (error != nil) {
|
||||
// // status code or network error
|
||||
// } else {
|
||||
// // succeeded
|
||||
// }
|
||||
// }];
|
||||
|
||||
//
|
||||
// NOTE: Fetches may retrieve data from the server even though the server
|
||||
// returned an error. The failure selector is called when the server
|
||||
// status is >= 300, with an NSError having domain
|
||||
// kGTMHTTPFetcherStatusDomain and code set to the server status.
|
||||
//
|
||||
// Status codes are at <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>
|
||||
//
|
||||
//
|
||||
// Threading and queue support:
|
||||
//
|
||||
// Callbacks require either that the thread used to start the fetcher have a run
|
||||
// loop spinning (typically the main thread), or that an NSOperationQueue be
|
||||
// provided upon which the delegate callbacks will be called. Starting with
|
||||
// iOS 6 and Mac OS X 10.7, clients may simply create an operation queue for
|
||||
// callbacks on a background thread:
|
||||
//
|
||||
// NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
|
||||
// [queue setMaxConcurrentOperationCount:1];
|
||||
// fetcher.delegateQueue = queue;
|
||||
//
|
||||
// or specify the main queue for callbacks on the main thread:
|
||||
//
|
||||
// fetcher.delegateQueue = [NSOperationQueue mainQueue];
|
||||
//
|
||||
// The client may also re-dispatch from the callbacks and notifications to
|
||||
// a known dispatch queue:
|
||||
//
|
||||
// [myFetcher beginFetchWithCompletionHandler:^(NSData *retrievedData, NSError *error) {
|
||||
// if (error == nil) {
|
||||
// dispatch_async(myDispatchQueue, ^{
|
||||
// ...
|
||||
// });
|
||||
// }
|
||||
// }];
|
||||
//
|
||||
//
|
||||
//
|
||||
// Downloading to disk:
|
||||
//
|
||||
// To have downloaded data saved directly to disk, specify either a path for the
|
||||
// downloadPath property, or a file handle for the downloadFileHandle property.
|
||||
// When downloading to disk, callbacks will be passed a nil for the NSData*
|
||||
// arguments.
|
||||
//
|
||||
//
|
||||
// HTTP methods and headers:
|
||||
//
|
||||
// Alternative HTTP methods, like PUT, and custom headers can be specified by
|
||||
// creating the fetcher with an appropriate NSMutableURLRequest
|
||||
//
|
||||
//
|
||||
// Proxies:
|
||||
//
|
||||
// Proxy handling is invisible so long as the system has a valid credential in
|
||||
// the keychain, which is normally true (else most NSURL-based apps would have
|
||||
// difficulty.) But when there is a proxy authetication error, the the fetcher
|
||||
// will call the failedWithError: method with the NSURLChallenge in the error's
|
||||
// userInfo. The error method can get the challenge info like this:
|
||||
//
|
||||
// NSURLAuthenticationChallenge *challenge
|
||||
// = [[error userInfo] objectForKey:kGTMHTTPFetcherErrorChallengeKey];
|
||||
// BOOL isProxyChallenge = [[challenge protectionSpace] isProxy];
|
||||
//
|
||||
// If a proxy error occurs, you can ask the user for the proxy username/password
|
||||
// and call fetcher's setProxyCredential: to provide those for the
|
||||
// next attempt to fetch.
|
||||
//
|
||||
//
|
||||
// Cookies:
|
||||
//
|
||||
// There are three supported mechanisms for remembering cookies between fetches.
|
||||
//
|
||||
// By default, GTMHTTPFetcher uses a mutable array held statically to track
|
||||
// cookies for all instantiated fetchers. This avoids server cookies being set
|
||||
// by servers for the application from interfering with Safari cookie settings,
|
||||
// and vice versa. The fetcher cookies are lost when the application quits.
|
||||
//
|
||||
// To rely instead on WebKit's global NSHTTPCookieStorage, call
|
||||
// setCookieStorageMethod: with kGTMHTTPFetcherCookieStorageMethodSystemDefault.
|
||||
//
|
||||
// If the fetcher is created from a GTMHTTPFetcherService object
|
||||
// then the cookie storage mechanism is set to use the cookie storage in the
|
||||
// service object rather than the static storage.
|
||||
//
|
||||
//
|
||||
// Fetching for periodic checks:
|
||||
//
|
||||
// The fetcher object tracks ETag headers from responses and
|
||||
// provide an "If-None-Match" header. This allows the server to save
|
||||
// bandwidth by providing a status message instead of repeated response
|
||||
// data.
|
||||
//
|
||||
// To get this behavior, create the fetcher from an GTMHTTPFetcherService object
|
||||
// and look for a fetch callback error with code 304
|
||||
// (kGTMHTTPFetcherStatusNotModified) like this:
|
||||
//
|
||||
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error {
|
||||
// if ([error code] == kGTMHTTPFetcherStatusNotModified) {
|
||||
// // |data| is empty; use the data from the previous finishedWithData: for this URL
|
||||
// } else {
|
||||
// // handle other server status code
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Monitoring received data
|
||||
//
|
||||
// The optional received data selector can be set with setReceivedDataSelector:
|
||||
// and should have the signature
|
||||
//
|
||||
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher receivedData:(NSData *)dataReceivedSoFar;
|
||||
//
|
||||
// The number bytes received so far is available as [fetcher downloadedLength].
|
||||
// This number may go down if a redirect causes the download to begin again from
|
||||
// a new server.
|
||||
//
|
||||
// If supplied by the server, the anticipated total download size is available
|
||||
// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown
|
||||
// download sizes.)
|
||||
//
|
||||
//
|
||||
// Automatic retrying of fetches
|
||||
//
|
||||
// The fetcher can optionally create a timer and reattempt certain kinds of
|
||||
// fetch failures (status codes 408, request timeout; 503, service unavailable;
|
||||
// 504, gateway timeout; networking errors NSURLErrorTimedOut and
|
||||
// NSURLErrorNetworkConnectionLost.) The user may set a retry selector to
|
||||
// customize the type of errors which will be retried.
|
||||
//
|
||||
// Retries are done in an exponential-backoff fashion (that is, after 1 second,
|
||||
// 2, 4, 8, and so on.)
|
||||
//
|
||||
// Enabling automatic retries looks like this:
|
||||
// [myFetcher setRetryEnabled:YES];
|
||||
//
|
||||
// With retries enabled, the success or failure callbacks are called only
|
||||
// when no more retries will be attempted. Calling the fetcher's stopFetching
|
||||
// method will terminate the retry timer, without the finished or failure
|
||||
// selectors being invoked.
|
||||
//
|
||||
// Optionally, the client may set the maximum retry interval:
|
||||
// [myFetcher setMaxRetryInterval:60.0]; // in seconds; default is 60 seconds
|
||||
// // for downloads, 600 for uploads
|
||||
//
|
||||
// Also optionally, the client may provide a callback selector to determine
|
||||
// if a status code or other error should be retried.
|
||||
// [myFetcher setRetrySelector:@selector(myFetcher:willRetry:forError:)];
|
||||
//
|
||||
// If set, the retry selector should have the signature:
|
||||
// -(BOOL)fetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
|
||||
// and return YES to set the retry timer or NO to fail without additional
|
||||
// fetch attempts.
|
||||
//
|
||||
// The retry method may return the |suggestedWillRetry| argument to get the
|
||||
// default retry behavior. Server status codes are present in the
|
||||
// error argument, and have the domain kGTMHTTPFetcherStatusDomain. The
|
||||
// user's method may look something like this:
|
||||
//
|
||||
// -(BOOL)myFetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error {
|
||||
//
|
||||
// // perhaps examine [error domain] and [error code], or [fetcher retryCount]
|
||||
// //
|
||||
// // return YES to start the retry timer, NO to proceed to the failure
|
||||
// // callback, or |suggestedWillRetry| to get default behavior for the
|
||||
// // current error domain and code values.
|
||||
// return suggestedWillRetry;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(GTL_TARGET_NAMESPACE)
|
||||
// we're using target namespace macros
|
||||
#import "GTLDefines.h"
|
||||
#elif defined(GDATA_TARGET_NAMESPACE)
|
||||
#import "GDataDefines.h"
|
||||
#else
|
||||
#if TARGET_OS_IPHONE
|
||||
#ifndef GTM_FOUNDATION_ONLY
|
||||
#define GTM_FOUNDATION_ONLY 1
|
||||
#endif
|
||||
#ifndef GTM_IPHONE
|
||||
#define GTM_IPHONE 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 40000)
|
||||
#define GTM_BACKGROUND_FETCHING 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// notifications
|
||||
//
|
||||
// fetch started and stopped, and fetch retry delay started and stopped
|
||||
extern NSString *const kGTMHTTPFetcherStartedNotification;
|
||||
extern NSString *const kGTMHTTPFetcherStoppedNotification;
|
||||
extern NSString *const kGTMHTTPFetcherRetryDelayStartedNotification;
|
||||
extern NSString *const kGTMHTTPFetcherRetryDelayStoppedNotification;
|
||||
|
||||
// callback constants
|
||||
extern NSString *const kGTMHTTPFetcherErrorDomain;
|
||||
extern NSString *const kGTMHTTPFetcherStatusDomain;
|
||||
extern NSString *const kGTMHTTPFetcherErrorChallengeKey;
|
||||
extern NSString *const kGTMHTTPFetcherStatusDataKey; // data returned with a kGTMHTTPFetcherStatusDomain error
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
kGTMHTTPFetcherErrorDownloadFailed = -1,
|
||||
kGTMHTTPFetcherErrorAuthenticationChallengeFailed = -2,
|
||||
kGTMHTTPFetcherErrorChunkUploadFailed = -3,
|
||||
kGTMHTTPFetcherErrorFileHandleException = -4,
|
||||
kGTMHTTPFetcherErrorBackgroundExpiration = -6,
|
||||
|
||||
// The code kGTMHTTPFetcherErrorAuthorizationFailed (-5) has been removed;
|
||||
// look for status 401 instead.
|
||||
|
||||
kGTMHTTPFetcherStatusNotModified = 304,
|
||||
kGTMHTTPFetcherStatusBadRequest = 400,
|
||||
kGTMHTTPFetcherStatusUnauthorized = 401,
|
||||
kGTMHTTPFetcherStatusForbidden = 403,
|
||||
kGTMHTTPFetcherStatusPreconditionFailed = 412
|
||||
};
|
||||
|
||||
// cookie storage methods
|
||||
enum {
|
||||
kGTMHTTPFetcherCookieStorageMethodStatic = 0,
|
||||
kGTMHTTPFetcherCookieStorageMethodFetchHistory = 1,
|
||||
kGTMHTTPFetcherCookieStorageMethodSystemDefault = 2,
|
||||
kGTMHTTPFetcherCookieStorageMethodNone = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void GTMAssertSelectorNilOrImplementedWithArgs(id obj, SEL sel, ...);
|
||||
|
||||
// Utility functions for applications self-identifying to servers via a
|
||||
// user-agent header
|
||||
|
||||
// Make a proper app name without whitespace from the given string, removing
|
||||
// whitespace and other characters that may be special parsed marks of
|
||||
// the full user-agent string.
|
||||
NSString *GTMCleanedUserAgentString(NSString *str);
|
||||
|
||||
// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1"
|
||||
NSString *GTMSystemVersionString(void);
|
||||
|
||||
// Make a generic name and version for the current application, like
|
||||
// com.example.MyApp/1.2.3 relying on the bundle identifier and the
|
||||
// CFBundleShortVersionString or CFBundleVersion. If no bundle ID
|
||||
// is available, the process name preceded by "proc_" is used.
|
||||
NSString *GTMApplicationIdentifier(NSBundle *bundle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@class GTMHTTPFetcher;
|
||||
|
||||
@protocol GTMCookieStorageProtocol <NSObject>
|
||||
// This protocol allows us to call into the service without requiring
|
||||
// GTMCookieStorage sources in this project
|
||||
//
|
||||
// The public interface for cookie handling is the GTMCookieStorage class,
|
||||
// accessible from a fetcher service object's fetchHistory or from the fetcher's
|
||||
// +staticCookieStorage method.
|
||||
- (NSArray *)cookiesForURL:(NSURL *)theURL;
|
||||
- (void)setCookies:(NSArray *)newCookies;
|
||||
@end
|
||||
|
||||
@protocol GTMHTTPFetchHistoryProtocol <NSObject>
|
||||
// This protocol allows us to call the fetch history object without requiring
|
||||
// GTMHTTPFetchHistory sources in this project
|
||||
- (void)updateRequest:(NSMutableURLRequest *)request isHTTPGet:(BOOL)isHTTPGet;
|
||||
- (BOOL)shouldCacheETaggedData;
|
||||
- (NSData *)cachedDataForRequest:(NSURLRequest *)request;
|
||||
- (id <GTMCookieStorageProtocol>)cookieStorage;
|
||||
- (void)updateFetchHistoryWithRequest:(NSURLRequest *)request
|
||||
response:(NSURLResponse *)response
|
||||
downloadedData:(NSData *)downloadedData;
|
||||
- (void)removeCachedDataForRequest:(NSURLRequest *)request;
|
||||
@end
|
||||
|
||||
@protocol GTMHTTPFetcherServiceProtocol <NSObject>
|
||||
// This protocol allows us to call into the service without requiring
|
||||
// GTMHTTPFetcherService sources in this project
|
||||
|
||||
@property (retain) NSOperationQueue *delegateQueue;
|
||||
|
||||
- (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher;
|
||||
- (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher;
|
||||
|
||||
- (GTMHTTPFetcher *)fetcherWithRequest:(NSURLRequest *)request;
|
||||
- (BOOL)isDelayingFetcher:(GTMHTTPFetcher *)fetcher;
|
||||
@end
|
||||
|
||||
@protocol GTMFetcherAuthorizationProtocol <NSObject>
|
||||
@required
|
||||
// This protocol allows us to call the authorizer without requiring its sources
|
||||
// in this project.
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
delegate:(id)delegate
|
||||
didFinishSelector:(SEL)sel;
|
||||
|
||||
- (void)stopAuthorization;
|
||||
|
||||
- (void)stopAuthorizationForRequest:(NSURLRequest *)request;
|
||||
|
||||
- (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
|
||||
|
||||
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
||||
|
||||
@property (retain, readonly) NSString *userEmail;
|
||||
|
||||
@optional
|
||||
|
||||
// Indicate if authorization may be attempted. Even if this succeeds,
|
||||
// authorization may fail if the user's permissions have been revoked.
|
||||
@property (readonly) BOOL canAuthorize;
|
||||
|
||||
// For development only, allow authorization of non-SSL requests, allowing
|
||||
// transmission of the bearer token unencrypted.
|
||||
@property (assign) BOOL shouldAuthorizeAllRequests;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
completionHandler:(void (^)(NSError *error))handler;
|
||||
#endif
|
||||
|
||||
@property (assign) id <GTMHTTPFetcherServiceProtocol> fetcherService; // WEAK
|
||||
|
||||
- (BOOL)primeForRefresh;
|
||||
|
||||
@end
|
||||
|
||||
// GTMHTTPFetcher objects are used for async retrieval of an http get or post
|
||||
//
|
||||
// See additional comments at the beginning of this file
|
||||
@interface GTMHTTPFetcher : NSObject {
|
||||
@protected
|
||||
NSMutableURLRequest *request_;
|
||||
NSURLConnection *connection_;
|
||||
NSMutableData *downloadedData_;
|
||||
NSString *downloadPath_;
|
||||
NSString *temporaryDownloadPath_;
|
||||
NSFileHandle *downloadFileHandle_;
|
||||
unsigned long long downloadedLength_;
|
||||
NSURLCredential *credential_; // username & password
|
||||
NSURLCredential *proxyCredential_; // credential supplied to proxy servers
|
||||
NSData *postData_;
|
||||
NSInputStream *postStream_;
|
||||
NSMutableData *loggedStreamData_;
|
||||
NSURLResponse *response_; // set in connection:didReceiveResponse:
|
||||
id delegate_;
|
||||
SEL finishedSel_; // should by implemented by delegate
|
||||
SEL sentDataSel_; // optional, set with setSentDataSelector
|
||||
SEL receivedDataSel_; // optional, set with setReceivedDataSelector
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
void (^completionBlock_)(NSData *, NSError *);
|
||||
void (^receivedDataBlock_)(NSData *);
|
||||
void (^sentDataBlock_)(NSInteger, NSInteger, NSInteger);
|
||||
BOOL (^retryBlock_)(BOOL, NSError *);
|
||||
#elif !__LP64__
|
||||
// placeholders: for 32-bit builds, keep the size of the object's ivar section
|
||||
// the same with and without blocks
|
||||
id completionPlaceholder_;
|
||||
id receivedDataPlaceholder_;
|
||||
id sentDataPlaceholder_;
|
||||
id retryPlaceholder_;
|
||||
#endif
|
||||
BOOL hasConnectionEnded_; // set if the connection need not be cancelled
|
||||
BOOL isCancellingChallenge_; // set only when cancelling an auth challenge
|
||||
BOOL isStopNotificationNeeded_; // set when start notification has been sent
|
||||
BOOL shouldFetchInBackground_;
|
||||
#if GTM_BACKGROUND_FETCHING
|
||||
NSUInteger backgroundTaskIdentifer_; // UIBackgroundTaskIdentifier
|
||||
#endif
|
||||
id userData_; // retained, if set by caller
|
||||
NSMutableDictionary *properties_; // more data retained for caller
|
||||
NSArray *runLoopModes_; // optional
|
||||
NSOperationQueue *delegateQueue_; // optional; available iOS 6/10.7 and later
|
||||
id <GTMHTTPFetchHistoryProtocol> fetchHistory_; // if supplied by the caller, used for Last-Modified-Since checks and cookies
|
||||
NSInteger cookieStorageMethod_; // constant from above
|
||||
id <GTMCookieStorageProtocol> cookieStorage_;
|
||||
|
||||
id <GTMFetcherAuthorizationProtocol> authorizer_;
|
||||
|
||||
// the service object that created and monitors this fetcher, if any
|
||||
id <GTMHTTPFetcherServiceProtocol> service_;
|
||||
NSString *serviceHost_;
|
||||
NSInteger servicePriority_;
|
||||
NSThread *thread_;
|
||||
|
||||
BOOL isRetryEnabled_; // user wants auto-retry
|
||||
SEL retrySel_; // optional; set with setRetrySelector
|
||||
NSTimer *retryTimer_;
|
||||
NSUInteger retryCount_;
|
||||
NSTimeInterval maxRetryInterval_; // default 600 seconds
|
||||
NSTimeInterval minRetryInterval_; // random between 1 and 2 seconds
|
||||
NSTimeInterval retryFactor_; // default interval multiplier is 2
|
||||
NSTimeInterval lastRetryInterval_;
|
||||
NSDate *initialRequestDate_;
|
||||
BOOL hasAttemptedAuthRefresh_;
|
||||
|
||||
NSString *comment_; // comment for log
|
||||
NSString *log_;
|
||||
#if !STRIP_GTM_FETCH_LOGGING
|
||||
NSURL *redirectedFromURL_;
|
||||
NSString *logRequestBody_;
|
||||
NSString *logResponseBody_;
|
||||
BOOL hasLoggedError_;
|
||||
BOOL shouldDeferResponseBodyLogging_;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a fetcher
|
||||
//
|
||||
// fetcherWithRequest will return an autoreleased fetcher, but if
|
||||
// the connection is successfully created, the connection should retain the
|
||||
// fetcher for the life of the connection as well. So the caller doesn't have
|
||||
// to retain the fetcher explicitly unless they want to be able to cancel it.
|
||||
+ (GTMHTTPFetcher *)fetcherWithRequest:(NSURLRequest *)request;
|
||||
|
||||
// Convenience methods that make a request, like +fetcherWithRequest
|
||||
+ (GTMHTTPFetcher *)fetcherWithURL:(NSURL *)requestURL;
|
||||
+ (GTMHTTPFetcher *)fetcherWithURLString:(NSString *)requestURLString;
|
||||
|
||||
// Designated initializer
|
||||
- (id)initWithRequest:(NSURLRequest *)request;
|
||||
|
||||
// Fetcher request
|
||||
//
|
||||
// The underlying request is mutable and may be modified by the caller
|
||||
@property (retain) NSMutableURLRequest *mutableRequest;
|
||||
|
||||
// Setting the credential is optional; it is used if the connection receives
|
||||
// an authentication challenge
|
||||
@property (retain) NSURLCredential *credential;
|
||||
|
||||
// Setting the proxy credential is optional; it is used if the connection
|
||||
// receives an authentication challenge from a proxy
|
||||
@property (retain) NSURLCredential *proxyCredential;
|
||||
|
||||
// If post data or stream is not set, then a GET retrieval method is assumed
|
||||
@property (retain) NSData *postData;
|
||||
@property (retain) NSInputStream *postStream;
|
||||
|
||||
// The default cookie storage method is kGTMHTTPFetcherCookieStorageMethodStatic
|
||||
// without a fetch history set, and kGTMHTTPFetcherCookieStorageMethodFetchHistory
|
||||
// with a fetch history set
|
||||
//
|
||||
// Applications needing control of cookies across a sequence of fetches should
|
||||
// create fetchers from a GTMHTTPFetcherService object (which encapsulates
|
||||
// fetch history) for a well-defined cookie store
|
||||
@property (assign) NSInteger cookieStorageMethod;
|
||||
|
||||
+ (id <GTMCookieStorageProtocol>)staticCookieStorage;
|
||||
|
||||
// Object to add authorization to the request, if needed
|
||||
@property (retain) id <GTMFetcherAuthorizationProtocol> authorizer;
|
||||
|
||||
// The service object that created and monitors this fetcher, if any
|
||||
@property (retain) id <GTMHTTPFetcherServiceProtocol> service;
|
||||
|
||||
// The host, if any, used to classify this fetcher in the fetcher service
|
||||
@property (copy) NSString *serviceHost;
|
||||
|
||||
// The priority, if any, used for starting fetchers in the fetcher service
|
||||
//
|
||||
// Lower values are higher priority; the default is 0, and values may
|
||||
// be negative or positive. This priority affects only the start order of
|
||||
// fetchers that are being delayed by a fetcher service.
|
||||
@property (assign) NSInteger servicePriority;
|
||||
|
||||
// The thread used to run this fetcher in the fetcher service when no operation
|
||||
// queue is provided.
|
||||
@property (retain) NSThread *thread;
|
||||
|
||||
// The delegate is retained during the connection
|
||||
@property (retain) id delegate;
|
||||
|
||||
// On iOS 4 and later, the fetch may optionally continue while the app is in the
|
||||
// background until finished or stopped by OS expiration
|
||||
//
|
||||
// The default value is NO
|
||||
//
|
||||
// For Mac OS X, background fetches are always supported, and this property
|
||||
// is ignored
|
||||
@property (assign) BOOL shouldFetchInBackground;
|
||||
|
||||
// The delegate's optional sentData selector may be used to monitor upload
|
||||
// progress. It should have a signature like:
|
||||
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher
|
||||
// didSendBytes:(NSInteger)bytesSent
|
||||
// totalBytesSent:(NSInteger)totalBytesSent
|
||||
// totalBytesExpectedToSend:(NSInteger)totalBytesExpectedToSend;
|
||||
//
|
||||
// +doesSupportSentDataCallback indicates if this delegate method is supported
|
||||
+ (BOOL)doesSupportSentDataCallback;
|
||||
|
||||
@property (assign) SEL sentDataSelector;
|
||||
|
||||
// The delegate's optional receivedData selector may be used to monitor download
|
||||
// progress. It should have a signature like:
|
||||
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher
|
||||
// receivedData:(NSData *)dataReceivedSoFar;
|
||||
//
|
||||
// The dataReceived argument will be nil when downloading to a path or to a
|
||||
// file handle.
|
||||
//
|
||||
// Applications should not use this method to accumulate the received data;
|
||||
// the callback method or block supplied to the beginFetch call will have
|
||||
// the complete NSData received.
|
||||
@property (assign) SEL receivedDataSelector;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
// The full interface to the block is provided rather than just a typedef for
|
||||
// its parameter list in order to get more useful code completion in the Xcode
|
||||
// editor
|
||||
@property (copy) void (^sentDataBlock)(NSInteger bytesSent, NSInteger totalBytesSent, NSInteger bytesExpectedToSend);
|
||||
|
||||
// The dataReceived argument will be nil when downloading to a path or to
|
||||
// a file handle
|
||||
@property (copy) void (^receivedDataBlock)(NSData *dataReceivedSoFar);
|
||||
#endif
|
||||
|
||||
// retrying; see comments at the top of the file. Calling
|
||||
// setRetryEnabled(YES) resets the min and max retry intervals.
|
||||
@property (assign, getter=isRetryEnabled) BOOL retryEnabled;
|
||||
|
||||
// Retry selector or block is optional for retries.
|
||||
//
|
||||
// If present, it should have the signature:
|
||||
// -(BOOL)fetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
|
||||
// and return YES to cause a retry. See comments at the top of this file.
|
||||
@property (assign) SEL retrySelector;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
@property (copy) BOOL (^retryBlock)(BOOL suggestedWillRetry, NSError *error);
|
||||
#endif
|
||||
|
||||
// Retry intervals must be strictly less than maxRetryInterval, else
|
||||
// they will be limited to maxRetryInterval and no further retries will
|
||||
// be attempted. Setting maxRetryInterval to 0.0 will reset it to the
|
||||
// default value, 600 seconds.
|
||||
|
||||
@property (assign) NSTimeInterval maxRetryInterval;
|
||||
|
||||
// Starting retry interval. Setting minRetryInterval to 0.0 will reset it
|
||||
// to a random value between 1.0 and 2.0 seconds. Clients should normally not
|
||||
// call this except for unit testing.
|
||||
@property (assign) NSTimeInterval minRetryInterval;
|
||||
|
||||
// Multiplier used to increase the interval between retries, typically 2.0.
|
||||
// Clients should not need to call this.
|
||||
@property (assign) double retryFactor;
|
||||
|
||||
// Number of retries attempted
|
||||
@property (readonly) NSUInteger retryCount;
|
||||
|
||||
// interval delay to precede next retry
|
||||
@property (readonly) NSTimeInterval nextRetryInterval;
|
||||
|
||||
// Begin fetching the request
|
||||
//
|
||||
// The delegate can optionally implement the finished selectors or pass NULL
|
||||
// for it.
|
||||
//
|
||||
// Returns YES if the fetch is initiated. The delegate is retained between
|
||||
// the beginFetch call until after the finish callback.
|
||||
//
|
||||
// An error is passed to the callback for server statuses 300 or
|
||||
// higher, with the status stored as the error object's code.
|
||||
//
|
||||
// finishedSEL has a signature like:
|
||||
// - (void)fetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error;
|
||||
//
|
||||
// If the application has specified a downloadPath or downloadFileHandle
|
||||
// for the fetcher, the data parameter passed to the callback will be nil.
|
||||
|
||||
- (BOOL)beginFetchWithDelegate:(id)delegate
|
||||
didFinishSelector:(SEL)finishedSEL;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
- (BOOL)beginFetchWithCompletionHandler:(void (^)(NSData *data, NSError *error))handler;
|
||||
#endif
|
||||
|
||||
|
||||
// Returns YES if this is in the process of fetching a URL
|
||||
- (BOOL)isFetching;
|
||||
|
||||
// Cancel the fetch of the request that's currently in progress
|
||||
- (void)stopFetching;
|
||||
|
||||
// Return the status code from the server response
|
||||
@property (readonly) NSInteger statusCode;
|
||||
|
||||
// Return the http headers from the response
|
||||
@property (retain, readonly) NSDictionary *responseHeaders;
|
||||
|
||||
// The response, once it's been received
|
||||
@property (retain) NSURLResponse *response;
|
||||
|
||||
// Bytes downloaded so far
|
||||
@property (readonly) unsigned long long downloadedLength;
|
||||
|
||||
// Buffer of currently-downloaded data
|
||||
@property (readonly, retain) NSData *downloadedData;
|
||||
|
||||
// Path in which to non-atomically create a file for storing the downloaded data
|
||||
//
|
||||
// The path must be set before fetching begins. The download file handle
|
||||
// will be created for the path, and can be used to monitor progress. If a file
|
||||
// already exists at the path, it will be overwritten.
|
||||
@property (copy) NSString *downloadPath;
|
||||
|
||||
// If downloadFileHandle is set, data received is immediately appended to
|
||||
// the file handle rather than being accumulated in the downloadedData property
|
||||
//
|
||||
// The file handle supplied must allow writing and support seekToFileOffset:,
|
||||
// and must be set before fetching begins. Setting a download path will
|
||||
// override the file handle property.
|
||||
@property (retain) NSFileHandle *downloadFileHandle;
|
||||
|
||||
// The optional fetchHistory object is used for a sequence of fetchers to
|
||||
// remember ETags, cache ETagged data, and store cookies. Typically, this
|
||||
// is set by a GTMFetcherService object when it creates a fetcher.
|
||||
//
|
||||
// Side effect: setting fetch history implicitly calls setCookieStorageMethod:
|
||||
@property (retain) id <GTMHTTPFetchHistoryProtocol> fetchHistory;
|
||||
|
||||
// userData is retained for the convenience of the caller
|
||||
@property (retain) id userData;
|
||||
|
||||
// Stored property values are retained for the convenience of the caller
|
||||
@property (copy) NSMutableDictionary *properties;
|
||||
|
||||
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property
|
||||
- (id)propertyForKey:(NSString *)key;
|
||||
|
||||
- (void)addPropertiesFromDictionary:(NSDictionary *)dict;
|
||||
|
||||
// Comments are useful for logging
|
||||
@property (copy) NSString *comment;
|
||||
|
||||
- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
|
||||
// Log of request and response, if logging is enabled
|
||||
@property (copy) NSString *log;
|
||||
|
||||
// Callbacks can be invoked on an operation queue rather than via the run loop,
|
||||
// starting on 10.7 and iOS 6. If a delegate queue is supplied. the run loop
|
||||
// modes are ignored.
|
||||
@property (retain) NSOperationQueue *delegateQueue;
|
||||
|
||||
// Using the fetcher while a modal dialog is displayed requires setting the
|
||||
// run-loop modes to include NSModalPanelRunLoopMode
|
||||
@property (retain) NSArray *runLoopModes;
|
||||
|
||||
// Users who wish to replace GTMHTTPFetcher's use of NSURLConnection
|
||||
// can do so globally here. The replacement should be a subclass of
|
||||
// NSURLConnection.
|
||||
+ (Class)connectionClass;
|
||||
+ (void)setConnectionClass:(Class)theClass;
|
||||
|
||||
// Spin the run loop, discarding events, until the fetch has completed
|
||||
//
|
||||
// This is only for use in testing or in tools without a user interface.
|
||||
//
|
||||
// Synchronous fetches should never be done by shipping apps; they are
|
||||
// sufficient reason for rejection from the app store.
|
||||
- (void)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
||||
|
||||
#if STRIP_GTM_FETCH_LOGGING
|
||||
// if logging is stripped, provide a stub for the main method
|
||||
// for controlling logging
|
||||
+ (void)setLoggingEnabled:(BOOL)flag;
|
||||
#endif // STRIP_GTM_FETCH_LOGGING
|
||||
|
||||
@end
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,350 @@
|
|||
/* Copyright (c) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
||||
|
||||
// This class implements the OAuth 2 protocol for authorizing requests.
|
||||
// http://tools.ietf.org/html/draft-ietf-oauth-v2
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// GTMHTTPFetcher.h brings in GTLDefines/GDataDefines
|
||||
#import "GTMHTTPFetcher.h"
|
||||
|
||||
// Until all OAuth 2 providers are up to the same spec, we'll provide a crude
|
||||
// way here to override the "Bearer" string in the Authorization header
|
||||
#ifndef GTM_OAUTH2_BEARER
|
||||
#define GTM_OAUTH2_BEARER "Bearer"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Service provider name allows stored authorization to be associated with
|
||||
// the authorizing service
|
||||
extern NSString *const kGTMOAuth2ServiceProviderGoogle;
|
||||
|
||||
//
|
||||
// GTMOAuth2SignIn constants, included here for use by clients
|
||||
//
|
||||
extern NSString *const kGTMOAuth2ErrorDomain;
|
||||
|
||||
// Error userInfo keys
|
||||
extern NSString *const kGTMOAuth2ErrorMessageKey;
|
||||
extern NSString *const kGTMOAuth2ErrorRequestKey;
|
||||
extern NSString *const kGTMOAuth2ErrorJSONKey;
|
||||
|
||||
enum {
|
||||
// Error code indicating that the window was prematurely closed
|
||||
kGTMOAuth2ErrorWindowClosed = -1000,
|
||||
kGTMOAuth2ErrorAuthorizationFailed = -1001,
|
||||
kGTMOAuth2ErrorTokenExpired = -1002,
|
||||
kGTMOAuth2ErrorTokenUnavailable = -1003,
|
||||
kGTMOAuth2ErrorUnauthorizableRequest = -1004
|
||||
};
|
||||
|
||||
|
||||
// Notifications for token fetches
|
||||
extern NSString *const kGTMOAuth2FetchStarted;
|
||||
extern NSString *const kGTMOAuth2FetchStopped;
|
||||
|
||||
extern NSString *const kGTMOAuth2FetcherKey;
|
||||
extern NSString *const kGTMOAuth2FetchTypeKey;
|
||||
extern NSString *const kGTMOAuth2FetchTypeToken;
|
||||
extern NSString *const kGTMOAuth2FetchTypeRefresh;
|
||||
extern NSString *const kGTMOAuth2FetchTypeAssertion;
|
||||
extern NSString *const kGTMOAuth2FetchTypeUserInfo;
|
||||
|
||||
// Token-issuance errors
|
||||
extern NSString *const kGTMOAuth2ErrorKey;
|
||||
extern NSString *const kGTMOAuth2ErrorObjectKey;
|
||||
|
||||
extern NSString *const kGTMOAuth2ErrorInvalidRequest;
|
||||
extern NSString *const kGTMOAuth2ErrorInvalidClient;
|
||||
extern NSString *const kGTMOAuth2ErrorInvalidGrant;
|
||||
extern NSString *const kGTMOAuth2ErrorUnauthorizedClient;
|
||||
extern NSString *const kGTMOAuth2ErrorUnsupportedGrantType;
|
||||
extern NSString *const kGTMOAuth2ErrorInvalidScope;
|
||||
|
||||
// Notification that sign-in has completed, and token fetches will begin (useful
|
||||
// for displaying interstitial messages after the window has closed)
|
||||
extern NSString *const kGTMOAuth2UserSignedIn;
|
||||
|
||||
// Notification for token changes
|
||||
extern NSString *const kGTMOAuth2AccessTokenRefreshed;
|
||||
extern NSString *const kGTMOAuth2RefreshTokenChanged;
|
||||
extern NSString *const kGTMOAuth2AccessTokenRefreshFailed;
|
||||
|
||||
// Notification for WebView loading
|
||||
extern NSString *const kGTMOAuth2WebViewStartedLoading;
|
||||
extern NSString *const kGTMOAuth2WebViewStoppedLoading;
|
||||
extern NSString *const kGTMOAuth2WebViewKey;
|
||||
extern NSString *const kGTMOAuth2WebViewStopKindKey;
|
||||
extern NSString *const kGTMOAuth2WebViewFinished;
|
||||
extern NSString *const kGTMOAuth2WebViewFailed;
|
||||
extern NSString *const kGTMOAuth2WebViewCancelled;
|
||||
|
||||
// Notification for network loss during html sign-in display
|
||||
extern NSString *const kGTMOAuth2NetworkLost;
|
||||
extern NSString *const kGTMOAuth2NetworkFound;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@interface GTMOAuth2Authentication : NSObject <GTMFetcherAuthorizationProtocol> {
|
||||
@private
|
||||
NSString *clientID_;
|
||||
NSString *clientSecret_;
|
||||
NSString *redirectURI_;
|
||||
NSMutableDictionary *parameters_;
|
||||
|
||||
// authorization parameters
|
||||
NSURL *tokenURL_;
|
||||
NSDate *expirationDate_;
|
||||
|
||||
NSString *authorizationTokenKey_;
|
||||
|
||||
NSDictionary *additionalTokenRequestParameters_;
|
||||
NSDictionary *additionalGrantTypeRequestParameters_;
|
||||
|
||||
// queue of requests for authorization waiting for a valid access token
|
||||
GTMHTTPFetcher *refreshFetcher_;
|
||||
NSMutableArray *authorizationQueue_;
|
||||
|
||||
id <GTMHTTPFetcherServiceProtocol> fetcherService_; // WEAK
|
||||
|
||||
Class parserClass_;
|
||||
|
||||
BOOL shouldAuthorizeAllRequests_;
|
||||
|
||||
// arbitrary data retained for the user
|
||||
id userData_;
|
||||
NSMutableDictionary *properties_;
|
||||
}
|
||||
|
||||
// OAuth2 standard protocol parameters
|
||||
//
|
||||
// These should be the plain strings; any needed escaping will be provided by
|
||||
// the library.
|
||||
|
||||
// Request properties
|
||||
@property (copy) NSString *clientID;
|
||||
@property (copy) NSString *clientSecret;
|
||||
@property (copy) NSString *redirectURI;
|
||||
@property (retain) NSString *scope;
|
||||
@property (retain) NSString *tokenType;
|
||||
@property (retain) NSString *assertion;
|
||||
@property (retain) NSString *refreshScope;
|
||||
|
||||
// Apps may optionally add parameters here to be provided to the token
|
||||
// endpoint on token requests and refreshes.
|
||||
@property (retain) NSDictionary *additionalTokenRequestParameters;
|
||||
|
||||
// Apps may optionally add parameters here to be provided to the token
|
||||
// endpoint on specific token requests and refreshes, keyed by the grant_type.
|
||||
// For example, if a different "type" parameter is required for obtaining
|
||||
// the auth code and on refresh, this might be:
|
||||
//
|
||||
// viewController.authentication.additionalGrantTypeRequestParameters = @{
|
||||
// @"authorization_code" : @{ @"type" : @"code" },
|
||||
// @"refresh_token" : @{ @"type" : @"refresh" }
|
||||
// };
|
||||
@property (retain) NSDictionary *additionalGrantTypeRequestParameters;
|
||||
|
||||
// Response properties
|
||||
@property (retain) NSMutableDictionary *parameters;
|
||||
|
||||
@property (retain) NSString *accessToken;
|
||||
@property (retain) NSString *refreshToken;
|
||||
@property (retain) NSNumber *expiresIn;
|
||||
@property (retain) NSString *code;
|
||||
@property (retain) NSString *errorString;
|
||||
|
||||
// URL for obtaining access tokens
|
||||
@property (copy) NSURL *tokenURL;
|
||||
|
||||
// Calculated expiration date (expiresIn seconds added to the
|
||||
// time the access token was received.)
|
||||
@property (copy) NSDate *expirationDate;
|
||||
|
||||
// Service identifier, like "Google"; not used for authentication
|
||||
//
|
||||
// The provider name is just for allowing stored authorization to be associated
|
||||
// with the authorizing service.
|
||||
@property (copy) NSString *serviceProvider;
|
||||
|
||||
// User ID; not used for authentication
|
||||
@property (retain) NSString *userID;
|
||||
|
||||
// User email and verified status; not used for authentication
|
||||
//
|
||||
// The verified string can be checked with -boolValue. If the result is false,
|
||||
// then the email address is listed with the account on the server, but the
|
||||
// address has not been confirmed as belonging to the owner of the account.
|
||||
@property (retain) NSString *userEmail;
|
||||
@property (retain) NSString *userEmailIsVerified;
|
||||
|
||||
// Property indicating if this auth has a refresh or access token so is suitable
|
||||
// for authorizing a request. This does not guarantee that the token is valid.
|
||||
@property (readonly) BOOL canAuthorize;
|
||||
|
||||
// Property indicating if this object will authorize plain http request
|
||||
// (as well as any non-https requests.) Default is NO, only requests with the
|
||||
// scheme https are authorized, since security may be compromised if tokens
|
||||
// are sent over the wire using an unencrypted protocol like http.
|
||||
@property (assign) BOOL shouldAuthorizeAllRequests;
|
||||
|
||||
// userData is retained for the convenience of the caller
|
||||
@property (retain) id userData;
|
||||
|
||||
// Stored property values are retained for the convenience of the caller
|
||||
@property (retain) NSDictionary *properties;
|
||||
|
||||
// Property for the optional fetcher service instance to be used to create
|
||||
// fetchers
|
||||
//
|
||||
// Fetcher service objects retain authorizations, so this is weak to avoid
|
||||
// circular retains.
|
||||
@property (assign) id <GTMHTTPFetcherServiceProtocol> fetcherService; // WEAK
|
||||
|
||||
// Alternative JSON parsing class; this should implement the
|
||||
// GTMOAuth2ParserClass informal protocol. If this property is
|
||||
// not set, the class SBJSON must be available in the runtime.
|
||||
@property (assign) Class parserClass;
|
||||
|
||||
// Key for the response parameter used for the authorization header; by default,
|
||||
// "access_token" is used, but some servers may expect alternatives, like
|
||||
// "id_token".
|
||||
@property (copy) NSString *authorizationTokenKey;
|
||||
|
||||
// Convenience method for creating an authentication object
|
||||
+ (id)authenticationWithServiceProvider:(NSString *)serviceProvider
|
||||
tokenURL:(NSURL *)tokenURL
|
||||
redirectURI:(NSString *)redirectURI
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret;
|
||||
|
||||
// Clear out any authentication values, prepare for a new request fetch
|
||||
- (void)reset;
|
||||
|
||||
// Main authorization entry points
|
||||
//
|
||||
// These will refresh the access token, if necessary, add the access token to
|
||||
// the request, then invoke the callback.
|
||||
//
|
||||
// The request argument may be nil to just force a refresh of the access token,
|
||||
// if needed.
|
||||
//
|
||||
// NOTE: To avoid accidental leaks of bearer tokens, the request must
|
||||
// be for a URL with the scheme https unless the shouldAuthorizeAllRequests
|
||||
// property is set.
|
||||
|
||||
// The finish selector should have a signature matching
|
||||
// - (void)authentication:(GTMOAuth2Authentication *)auth
|
||||
// request:(NSMutableURLRequest *)request
|
||||
// finishedWithError:(NSError *)error;
|
||||
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
delegate:(id)delegate
|
||||
didFinishSelector:(SEL)sel;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
completionHandler:(void (^)(NSError *error))handler;
|
||||
#endif
|
||||
|
||||
// Synchronous entry point; authorizing this way cannot refresh an expired
|
||||
// access token
|
||||
- (BOOL)authorizeRequest:(NSMutableURLRequest *)request;
|
||||
|
||||
// If the authentication is waiting for a refresh to complete, spin the run
|
||||
// loop, discarding events, until the fetch has completed
|
||||
//
|
||||
// This is only for use in testing or in tools without a user interface.
|
||||
- (void)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Internal properties and methods for use by GTMOAuth2SignIn
|
||||
//
|
||||
|
||||
// Pending fetcher to get a new access token, if any
|
||||
@property (retain) GTMHTTPFetcher *refreshFetcher;
|
||||
|
||||
// Check if a request is queued up to be authorized
|
||||
- (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
|
||||
|
||||
// Check if a request appears to be authorized
|
||||
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
||||
|
||||
// Stop any pending refresh fetch. This will also cancel the authorization
|
||||
// for all fetch requests pending authorization.
|
||||
- (void)stopAuthorization;
|
||||
|
||||
// Prevents authorization callback for a given request.
|
||||
- (void)stopAuthorizationForRequest:(NSURLRequest *)request;
|
||||
|
||||
// OAuth fetch user-agent header value
|
||||
- (NSString *)userAgent;
|
||||
|
||||
// Parse and set token and token secret from response data
|
||||
- (void)setKeysForResponseString:(NSString *)str;
|
||||
- (void)setKeysForResponseDictionary:(NSDictionary *)dict;
|
||||
|
||||
// Persistent token string for keychain storage
|
||||
//
|
||||
// We'll use the format "refresh_token=foo&serviceProvider=bar" so we can
|
||||
// easily alter what portions of the auth data are stored
|
||||
//
|
||||
// Use these methods for serialization
|
||||
- (NSString *)persistenceResponseString;
|
||||
- (void)setKeysForPersistenceResponseString:(NSString *)str;
|
||||
|
||||
// method to begin fetching an access token, used by the sign-in object
|
||||
- (GTMHTTPFetcher *)beginTokenFetchWithDelegate:(id)delegate
|
||||
didFinishSelector:(SEL)finishedSel;
|
||||
|
||||
// Entry point to post a notification about a fetcher currently used for
|
||||
// obtaining or refreshing a token; the sign-in object will also use this
|
||||
// to indicate when the user's email address is being fetched.
|
||||
//
|
||||
// Fetch type constants are above under "notifications for token fetches"
|
||||
- (void)notifyFetchIsRunning:(BOOL)isStarting
|
||||
fetcher:(GTMHTTPFetcher *)fetcher
|
||||
type:(NSString *)fetchType;
|
||||
|
||||
// Arbitrary key-value properties retained for the user
|
||||
- (void)setProperty:(id)obj forKey:(NSString *)key;
|
||||
- (id)propertyForKey:(NSString *)key;
|
||||
|
||||
//
|
||||
// Utilities
|
||||
//
|
||||
|
||||
+ (NSString *)encodedOAuthValueForString:(NSString *)str;
|
||||
|
||||
+ (NSString *)encodedQueryParametersForDictionary:(NSDictionary *)dict;
|
||||
|
||||
+ (NSDictionary *)dictionaryWithResponseString:(NSString *)responseStr;
|
||||
|
||||
+ (NSDictionary *)dictionaryWithJSONData:(NSData *)data;
|
||||
|
||||
+ (NSString *)scopeWithStrings:(NSString *)firstStr, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
@end
|
||||
|
||||
#endif // GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,187 @@
|
|||
/* Copyright (c) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// This sign-in object opens and closes the web view window as needed for
|
||||
// users to sign in. For signing in to Google, it also obtains
|
||||
// the authenticated user's email address.
|
||||
//
|
||||
// Typically, this will be managed for the application by
|
||||
// GTMOAuth2ViewControllerTouch or GTMOAuth2WindowController, so this
|
||||
// class's interface is interesting only if
|
||||
// you are creating your own window controller for sign-in.
|
||||
//
|
||||
//
|
||||
// Delegate methods implemented by the window controller
|
||||
//
|
||||
// The window controller implements two methods for use by the sign-in object,
|
||||
// the webRequestSelector and the finishedSelector:
|
||||
//
|
||||
// webRequestSelector has a signature matching
|
||||
// - (void)signIn:(GTMOAuth2SignIn *)signIn displayRequest:(NSURLRequest *)request
|
||||
//
|
||||
// The web request selector will be invoked with a request to be displayed, or
|
||||
// nil to close the window when the final callback request has been encountered.
|
||||
//
|
||||
//
|
||||
// finishedSelector has a signature matching
|
||||
// - (void)signin:(GTMOAuth2SignIn *)signin finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
|
||||
//
|
||||
// The finished selector will be invoked when sign-in has completed, except
|
||||
// when explicitly canceled by calling cancelSigningIn
|
||||
//
|
||||
|
||||
#if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
// GTMHTTPFetcher brings in GTLDefines/GDataDefines
|
||||
#import "GTMHTTPFetcher.h"
|
||||
|
||||
#import "GTMOAuth2Authentication.h"
|
||||
|
||||
@interface GTMOAuth2SignIn : NSObject {
|
||||
@private
|
||||
GTMOAuth2Authentication *auth_;
|
||||
|
||||
// the endpoint for displaying the sign-in page
|
||||
NSURL *authorizationURL_;
|
||||
NSDictionary *additionalAuthorizationParameters_;
|
||||
|
||||
id delegate_;
|
||||
SEL webRequestSelector_;
|
||||
SEL finishedSelector_;
|
||||
|
||||
BOOL hasHandledCallback_;
|
||||
|
||||
GTMHTTPFetcher *pendingFetcher_;
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
BOOL shouldFetchGoogleUserEmail_;
|
||||
BOOL shouldFetchGoogleUserProfile_;
|
||||
NSDictionary *userProfile_;
|
||||
#endif
|
||||
|
||||
SCNetworkReachabilityRef reachabilityRef_;
|
||||
NSTimer *networkLossTimer_;
|
||||
NSTimeInterval networkLossTimeoutInterval_;
|
||||
BOOL hasNotifiedNetworkLoss_;
|
||||
|
||||
id userData_;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) GTMOAuth2Authentication *authentication;
|
||||
|
||||
@property (nonatomic, retain) NSURL *authorizationURL;
|
||||
@property (nonatomic, retain) NSDictionary *additionalAuthorizationParameters;
|
||||
|
||||
// The delegate is released when signing in finishes or is cancelled
|
||||
@property (nonatomic, retain) id delegate;
|
||||
@property (nonatomic, assign) SEL webRequestSelector;
|
||||
@property (nonatomic, assign) SEL finishedSelector;
|
||||
|
||||
@property (nonatomic, retain) id userData;
|
||||
|
||||
// By default, signing in to Google will fetch the user's email, but will not
|
||||
// fetch the user's profile.
|
||||
//
|
||||
// The email is saved in the auth object.
|
||||
// The profile is available immediately after sign-in.
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
@property (nonatomic, assign) BOOL shouldFetchGoogleUserEmail;
|
||||
@property (nonatomic, assign) BOOL shouldFetchGoogleUserProfile;
|
||||
@property (nonatomic, retain, readonly) NSDictionary *userProfile;
|
||||
#endif
|
||||
|
||||
// The default timeout for an unreachable network during display of the
|
||||
// sign-in page is 30 seconds; set this to 0 to have no timeout
|
||||
@property (nonatomic, assign) NSTimeInterval networkLossTimeoutInterval;
|
||||
|
||||
// The delegate is retained until sign-in has completed or been canceled
|
||||
//
|
||||
// designated initializer
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
delegate:(id)delegate
|
||||
webRequestSelector:(SEL)webRequestSelector
|
||||
finishedSelector:(SEL)finishedSelector;
|
||||
|
||||
// A default authentication object for signing in to Google services
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (GTMOAuth2Authentication *)standardGoogleAuthenticationForScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret;
|
||||
#endif
|
||||
|
||||
#pragma mark Methods used by the Window Controller
|
||||
|
||||
// Start the sequence of fetches and sign-in window display for sign-in
|
||||
- (BOOL)startSigningIn;
|
||||
|
||||
// Stop any pending fetches, and close the window (but don't call the
|
||||
// delegate's finishedSelector)
|
||||
- (void)cancelSigningIn;
|
||||
|
||||
// Window controllers must tell the sign-in object about any redirect
|
||||
// requested by the web view, and any changes in the webview window title
|
||||
//
|
||||
// If these return YES then the event was handled by the
|
||||
// sign-in object (typically by closing the window) and should be ignored by
|
||||
// the window controller's web view
|
||||
|
||||
- (BOOL)requestRedirectedToRequest:(NSURLRequest *)redirectedRequest;
|
||||
- (BOOL)titleChanged:(NSString *)title;
|
||||
- (BOOL)cookiesChanged:(NSHTTPCookieStorage *)cookieStorage;
|
||||
- (BOOL)loadFailedWithError:(NSError *)error;
|
||||
|
||||
// Window controllers must tell the sign-in object if the window was closed
|
||||
// prematurely by the user (but not by the sign-in object); this calls the
|
||||
// delegate's finishedSelector
|
||||
- (void)windowWasClosed;
|
||||
|
||||
// Start the sequences for signing in with an authorization code. The
|
||||
// authentication must contain an authorization code, otherwise the process
|
||||
// will fail.
|
||||
- (void)authCodeObtained;
|
||||
|
||||
#pragma mark -
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
// Revocation of an authorized token from Google
|
||||
+ (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth;
|
||||
|
||||
// Create a fetcher for obtaining the user's Google email address or profile,
|
||||
// according to the current auth scopes.
|
||||
//
|
||||
// The auth object must have been created with appropriate scopes.
|
||||
//
|
||||
// The fetcher's response data can be parsed with NSJSONSerialization.
|
||||
+ (GTMHTTPFetcher *)userInfoFetcherWithAuth:(GTMOAuth2Authentication *)auth;
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// Standard authentication values
|
||||
+ (NSString *)nativeClientRedirectURI;
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (NSURL *)googleAuthorizationURL;
|
||||
+ (NSURL *)googleTokenURL;
|
||||
+ (NSURL *)googleUserInfoURL;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#endif // #if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
|
@ -0,0 +1,942 @@
|
|||
/* Copyright (c) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
||||
|
||||
#import "GTMOAuth2SignIn.h"
|
||||
|
||||
// we'll default to timing out if the network becomes unreachable for more
|
||||
// than 30 seconds when the sign-in page is displayed
|
||||
static const NSTimeInterval kDefaultNetworkLossTimeoutInterval = 30.0;
|
||||
|
||||
// URI indicating an installed app is signing in. This is described at
|
||||
//
|
||||
// http://code.google.com/apis/accounts/docs/OAuth2.html#IA
|
||||
//
|
||||
NSString *const kOOBString = @"urn:ietf:wg:oauth:2.0:oob";
|
||||
|
||||
|
||||
@interface GTMOAuth2SignIn ()
|
||||
@property (assign) BOOL hasHandledCallback;
|
||||
@property (retain) GTMHTTPFetcher *pendingFetcher;
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
@property (nonatomic, retain, readwrite) NSDictionary *userProfile;
|
||||
#endif
|
||||
|
||||
- (void)invokeFinalCallbackWithError:(NSError *)error;
|
||||
|
||||
- (BOOL)startWebRequest;
|
||||
+ (NSMutableURLRequest *)mutableURLRequestWithURL:(NSURL *)oldURL
|
||||
paramString:(NSString *)paramStr;
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
- (void)addScopeForGoogleUserInfo;
|
||||
- (void)fetchGoogleUserInfo;
|
||||
#endif
|
||||
- (void)finishSignInWithError:(NSError *)error;
|
||||
|
||||
- (void)auth:(GTMOAuth2Authentication *)auth
|
||||
finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
error:(NSError *)error;
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
- (void)infoFetcher:(GTMHTTPFetcher *)fetcher
|
||||
finishedWithData:(NSData *)data
|
||||
error:(NSError *)error;
|
||||
+ (NSData *)decodeWebSafeBase64:(NSString *)base64Str;
|
||||
- (void)updateGoogleUserInfoWithData:(NSData *)data;
|
||||
#endif
|
||||
|
||||
- (void)closeTheWindow;
|
||||
|
||||
- (void)startReachabilityCheck;
|
||||
- (void)stopReachabilityCheck;
|
||||
- (void)reachabilityTarget:(SCNetworkReachabilityRef)reachabilityRef
|
||||
changedFlags:(SCNetworkConnectionFlags)flags;
|
||||
- (void)reachabilityTimerFired:(NSTimer *)timer;
|
||||
@end
|
||||
|
||||
@implementation GTMOAuth2SignIn
|
||||
|
||||
@synthesize authentication = auth_;
|
||||
|
||||
@synthesize authorizationURL = authorizationURL_;
|
||||
@synthesize additionalAuthorizationParameters = additionalAuthorizationParameters_;
|
||||
|
||||
@synthesize delegate = delegate_;
|
||||
@synthesize webRequestSelector = webRequestSelector_;
|
||||
@synthesize finishedSelector = finishedSelector_;
|
||||
@synthesize hasHandledCallback = hasHandledCallback_;
|
||||
@synthesize pendingFetcher = pendingFetcher_;
|
||||
@synthesize userData = userData_;
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
@synthesize shouldFetchGoogleUserEmail = shouldFetchGoogleUserEmail_;
|
||||
@synthesize shouldFetchGoogleUserProfile = shouldFetchGoogleUserProfile_;
|
||||
@synthesize userProfile = userProfile_;
|
||||
#endif
|
||||
|
||||
@synthesize networkLossTimeoutInterval = networkLossTimeoutInterval_;
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (NSURL *)googleAuthorizationURL {
|
||||
NSString *str = @"https://accounts.google.com/o/oauth2/auth";
|
||||
return [NSURL URLWithString:str];
|
||||
}
|
||||
|
||||
+ (NSURL *)googleTokenURL {
|
||||
NSString *str = @"https://accounts.google.com/o/oauth2/token";
|
||||
return [NSURL URLWithString:str];
|
||||
}
|
||||
|
||||
+ (NSURL *)googleRevocationURL {
|
||||
NSString *urlStr = @"https://accounts.google.com/o/oauth2/revoke";
|
||||
return [NSURL URLWithString:urlStr];
|
||||
}
|
||||
|
||||
+ (NSURL *)googleUserInfoURL {
|
||||
NSString *urlStr = @"https://www.googleapis.com/oauth2/v3/userinfo";
|
||||
return [NSURL URLWithString:urlStr];
|
||||
}
|
||||
#endif
|
||||
|
||||
+ (NSString *)nativeClientRedirectURI {
|
||||
return kOOBString;
|
||||
}
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (GTMOAuth2Authentication *)standardGoogleAuthenticationForScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret {
|
||||
NSString *redirectURI = [self nativeClientRedirectURI];
|
||||
NSURL *tokenURL = [self googleTokenURL];
|
||||
|
||||
GTMOAuth2Authentication *auth;
|
||||
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:kGTMOAuth2ServiceProviderGoogle
|
||||
tokenURL:tokenURL
|
||||
redirectURI:redirectURI
|
||||
clientID:clientID
|
||||
clientSecret:clientSecret];
|
||||
auth.scope = scope;
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
- (void)addScopeForGoogleUserInfo {
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
if (self.shouldFetchGoogleUserEmail) {
|
||||
NSString *const emailScope = @"https://www.googleapis.com/auth/userinfo.email";
|
||||
NSString *scope = auth.scope;
|
||||
if ([scope rangeOfString:emailScope].location == NSNotFound) {
|
||||
scope = [GTMOAuth2Authentication scopeWithStrings:scope, emailScope, nil];
|
||||
auth.scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.shouldFetchGoogleUserProfile) {
|
||||
NSString *const profileScope = @"https://www.googleapis.com/auth/userinfo.profile";
|
||||
NSString *scope = auth.scope;
|
||||
if ([scope rangeOfString:profileScope].location == NSNotFound) {
|
||||
scope = [GTMOAuth2Authentication scopeWithStrings:scope, profileScope, nil];
|
||||
auth.scope = scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
delegate:(id)delegate
|
||||
webRequestSelector:(SEL)webRequestSelector
|
||||
finishedSelector:(SEL)finishedSelector {
|
||||
// check the selectors on debug builds
|
||||
GTMAssertSelectorNilOrImplementedWithArgs(delegate, webRequestSelector,
|
||||
@encode(GTMOAuth2SignIn *), @encode(NSURLRequest *), 0);
|
||||
GTMAssertSelectorNilOrImplementedWithArgs(delegate, finishedSelector,
|
||||
@encode(GTMOAuth2SignIn *), @encode(GTMOAuth2Authentication *),
|
||||
@encode(NSError *), 0);
|
||||
|
||||
// designated initializer
|
||||
self = [super init];
|
||||
if (self) {
|
||||
auth_ = [auth retain];
|
||||
authorizationURL_ = [authorizationURL retain];
|
||||
delegate_ = [delegate retain];
|
||||
webRequestSelector_ = webRequestSelector;
|
||||
finishedSelector_ = finishedSelector;
|
||||
|
||||
// for Google authentication, we want to automatically fetch user info
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
NSString *host = [authorizationURL host];
|
||||
if ([host hasSuffix:@".google.com"]) {
|
||||
shouldFetchGoogleUserEmail_ = YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
// default timeout for a lost internet connection while the server
|
||||
// UI is displayed is 30 seconds
|
||||
networkLossTimeoutInterval_ = kDefaultNetworkLossTimeoutInterval;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self stopReachabilityCheck];
|
||||
|
||||
[auth_ release];
|
||||
[authorizationURL_ release];
|
||||
[additionalAuthorizationParameters_ release];
|
||||
[delegate_ release];
|
||||
[pendingFetcher_ release];
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
[userProfile_ release];
|
||||
#endif
|
||||
[userData_ release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark Sign-in Sequence Methods
|
||||
|
||||
// stop any pending fetches, and close the window (but don't call the
|
||||
// delegate's finishedSelector)
|
||||
- (void)cancelSigningIn {
|
||||
[self.pendingFetcher stopFetching];
|
||||
self.pendingFetcher = nil;
|
||||
|
||||
[self.authentication stopAuthorization];
|
||||
|
||||
[self closeTheWindow];
|
||||
|
||||
[delegate_ autorelease];
|
||||
delegate_ = nil;
|
||||
}
|
||||
|
||||
//
|
||||
// This is the entry point to begin the sequence
|
||||
// - display the authentication web page, and monitor redirects
|
||||
// - exchange the code for an access token and a refresh token
|
||||
// - for Google sign-in, fetch the user's email address
|
||||
// - tell the delegate we're finished
|
||||
//
|
||||
- (BOOL)startSigningIn {
|
||||
// For signing in to Google, append the scope for obtaining the authenticated
|
||||
// user email and profile, as appropriate
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
[self addScopeForGoogleUserInfo];
|
||||
#endif
|
||||
|
||||
// start the authorization
|
||||
return [self startWebRequest];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)parametersForWebRequest {
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSString *clientID = auth.clientID;
|
||||
NSString *redirectURI = auth.redirectURI;
|
||||
|
||||
BOOL hasClientID = ([clientID length] > 0);
|
||||
BOOL hasRedirect = ([redirectURI length] > 0
|
||||
|| redirectURI == [[self class] nativeClientRedirectURI]);
|
||||
if (!hasClientID || !hasRedirect) {
|
||||
#if DEBUG
|
||||
NSAssert(hasClientID, @"GTMOAuth2SignIn: clientID needed");
|
||||
NSAssert(hasRedirect, @"GTMOAuth2SignIn: redirectURI needed");
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
// invoke the UI controller's web request selector to display
|
||||
// the authorization page
|
||||
|
||||
// add params to the authorization URL
|
||||
NSString *scope = auth.scope;
|
||||
if ([scope length] == 0) scope = nil;
|
||||
|
||||
NSMutableDictionary *paramsDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
@"code", @"response_type",
|
||||
clientID, @"client_id",
|
||||
scope, @"scope", // scope may be nil
|
||||
nil];
|
||||
if (redirectURI) {
|
||||
[paramsDict setObject:redirectURI forKey:@"redirect_uri"];
|
||||
}
|
||||
return paramsDict;
|
||||
}
|
||||
|
||||
- (BOOL)startWebRequest {
|
||||
NSMutableDictionary *paramsDict = [self parametersForWebRequest];
|
||||
|
||||
NSDictionary *additionalParams = self.additionalAuthorizationParameters;
|
||||
if (additionalParams) {
|
||||
[paramsDict addEntriesFromDictionary:additionalParams];
|
||||
}
|
||||
|
||||
NSString *paramStr = [GTMOAuth2Authentication encodedQueryParametersForDictionary:paramsDict];
|
||||
|
||||
NSURL *authorizationURL = self.authorizationURL;
|
||||
NSMutableURLRequest *request;
|
||||
request = [[self class] mutableURLRequestWithURL:authorizationURL
|
||||
paramString:paramStr];
|
||||
|
||||
[delegate_ performSelector:self.webRequestSelector
|
||||
withObject:self
|
||||
withObject:request];
|
||||
|
||||
// at this point, we're waiting on the server-driven html UI, so
|
||||
// we want notification if we lose connectivity to the web server
|
||||
[self startReachabilityCheck];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// utility for making a request from an old URL with some additional parameters
|
||||
+ (NSMutableURLRequest *)mutableURLRequestWithURL:(NSURL *)oldURL
|
||||
paramString:(NSString *)paramStr {
|
||||
if ([paramStr length] == 0) {
|
||||
return [NSMutableURLRequest requestWithURL:oldURL];
|
||||
}
|
||||
|
||||
NSString *query = [oldURL query];
|
||||
if ([query length] > 0) {
|
||||
query = [query stringByAppendingFormat:@"&%@", paramStr];
|
||||
} else {
|
||||
query = paramStr;
|
||||
}
|
||||
|
||||
NSString *portStr = @"";
|
||||
NSString *oldPort = [[oldURL port] stringValue];
|
||||
if ([oldPort length] > 0) {
|
||||
portStr = [@":" stringByAppendingString:oldPort];
|
||||
}
|
||||
|
||||
NSString *qMark = [query length] > 0 ? @"?" : @"";
|
||||
NSString *newURLStr = [NSString stringWithFormat:@"%@://%@%@%@%@%@",
|
||||
[oldURL scheme], [oldURL host], portStr,
|
||||
[oldURL path], qMark, query];
|
||||
NSURL *newURL = [NSURL URLWithString:newURLStr];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:newURL];
|
||||
return request;
|
||||
}
|
||||
|
||||
// entry point for the window controller to tell us that the window
|
||||
// prematurely closed
|
||||
- (void)windowWasClosed {
|
||||
[self stopReachabilityCheck];
|
||||
|
||||
NSError *error = [NSError errorWithDomain:kGTMOAuth2ErrorDomain
|
||||
code:kGTMOAuth2ErrorWindowClosed
|
||||
userInfo:nil];
|
||||
[self invokeFinalCallbackWithError:error];
|
||||
}
|
||||
|
||||
// internal method to tell the window controller to close the window
|
||||
- (void)closeTheWindow {
|
||||
[self stopReachabilityCheck];
|
||||
|
||||
// a nil request means the window should be closed
|
||||
[delegate_ performSelector:self.webRequestSelector
|
||||
withObject:self
|
||||
withObject:nil];
|
||||
}
|
||||
|
||||
// entry point for the window controller to tell us what web page has been
|
||||
// requested
|
||||
//
|
||||
// When the request is for the callback URL, this method invokes
|
||||
// authCodeObtained and returns YES
|
||||
- (BOOL)requestRedirectedToRequest:(NSURLRequest *)redirectedRequest {
|
||||
// for Google's installed app sign-in protocol, we'll look for the
|
||||
// end-of-sign-in indicator in the titleChanged: method below
|
||||
NSString *redirectURI = self.authentication.redirectURI;
|
||||
if (redirectURI == nil) return NO;
|
||||
|
||||
// when we're searching for the window title string, then we can ignore
|
||||
// redirects
|
||||
NSString *standardURI = [[self class] nativeClientRedirectURI];
|
||||
if (standardURI != nil && [redirectURI isEqual:standardURI]) return NO;
|
||||
|
||||
// compare the redirectURI, which tells us when the web sign-in is done,
|
||||
// to the actual redirection
|
||||
NSURL *redirectURL = [NSURL URLWithString:redirectURI];
|
||||
NSURL *requestURL = [redirectedRequest URL];
|
||||
|
||||
// avoid comparing to nil host and path values (such as when redirected to
|
||||
// "about:blank")
|
||||
NSString *requestHost = [requestURL host];
|
||||
NSString *requestPath = [requestURL path];
|
||||
BOOL isCallback;
|
||||
if (requestHost && requestPath) {
|
||||
isCallback = [[redirectURL host] isEqual:[requestURL host]]
|
||||
&& [[redirectURL path] isEqual:[requestURL path]];
|
||||
} else if (requestURL) {
|
||||
// handle "about:blank"
|
||||
isCallback = [redirectURL isEqual:requestURL];
|
||||
} else {
|
||||
isCallback = NO;
|
||||
}
|
||||
|
||||
if (!isCallback) {
|
||||
// tell the caller that this request is nothing interesting
|
||||
return NO;
|
||||
}
|
||||
|
||||
// we've reached the callback URL
|
||||
|
||||
// try to get the access code
|
||||
if (!self.hasHandledCallback) {
|
||||
NSString *responseStr = [[redirectedRequest URL] query];
|
||||
[self.authentication setKeysForResponseString:responseStr];
|
||||
|
||||
#if DEBUG
|
||||
NSAssert([self.authentication.code length] > 0
|
||||
|| [self.authentication.errorString length] > 0,
|
||||
@"response lacks auth code or error");
|
||||
#endif
|
||||
|
||||
[self authCodeObtained];
|
||||
}
|
||||
// tell the delegate that we did handle this request
|
||||
return YES;
|
||||
}
|
||||
|
||||
// entry point for the window controller to tell us when a new page title has
|
||||
// been loadded
|
||||
//
|
||||
// When the title indicates sign-in has completed, this method invokes
|
||||
// authCodeObtained and returns YES
|
||||
- (BOOL)titleChanged:(NSString *)title {
|
||||
// return YES if the OAuth flow ending title was detected
|
||||
|
||||
// right now we're just looking for a parameter list following the last space
|
||||
// in the title string, but hopefully we'll eventually get something better
|
||||
// from the server to search for
|
||||
NSRange paramsRange = [title rangeOfString:@" "
|
||||
options:NSBackwardsSearch];
|
||||
NSUInteger spaceIndex = paramsRange.location;
|
||||
if (spaceIndex != NSNotFound) {
|
||||
NSString *responseStr = [title substringFromIndex:(spaceIndex + 1)];
|
||||
|
||||
NSDictionary *dict = [GTMOAuth2Authentication dictionaryWithResponseString:responseStr];
|
||||
|
||||
NSString *code = [dict objectForKey:@"code"];
|
||||
NSString *error = [dict objectForKey:@"error"];
|
||||
if ([code length] > 0 || [error length] > 0) {
|
||||
|
||||
if (!self.hasHandledCallback) {
|
||||
[self.authentication setKeysForResponseDictionary:dict];
|
||||
|
||||
[self authCodeObtained];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)cookiesChanged:(NSHTTPCookieStorage *)cookieStorage {
|
||||
// We're ignoring these.
|
||||
return NO;
|
||||
};
|
||||
|
||||
// entry point for the window controller to tell us when a load has failed
|
||||
// in the webview
|
||||
//
|
||||
// if the initial authorization URL fails, bail out so the user doesn't
|
||||
// see an empty webview
|
||||
- (BOOL)loadFailedWithError:(NSError *)error {
|
||||
NSURL *authorizationURL = self.authorizationURL;
|
||||
NSURL *failedURL = [[error userInfo] valueForKey:@"NSErrorFailingURLKey"]; // NSURLErrorFailingURLErrorKey defined in 10.6
|
||||
|
||||
BOOL isAuthURL = [[failedURL host] isEqual:[authorizationURL host]]
|
||||
&& [[failedURL path] isEqual:[authorizationURL path]];
|
||||
|
||||
if (isAuthURL) {
|
||||
// We can assume that we have no pending fetchers, since we only
|
||||
// handle failure to load the initial authorization URL
|
||||
[self closeTheWindow];
|
||||
[self invokeFinalCallbackWithError:error];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)authCodeObtained {
|
||||
// the callback page was requested, or the authenticate code was loaded
|
||||
// into a page's title, so exchange the auth code for access & refresh tokens
|
||||
// and tell the window to close
|
||||
|
||||
// avoid duplicate signals that the callback point has been reached
|
||||
self.hasHandledCallback = YES;
|
||||
|
||||
// If the signin was request for exchanging an authentication token to a
|
||||
// refresh token, there is no window to close.
|
||||
if (self.webRequestSelector) {
|
||||
[self closeTheWindow];
|
||||
} else {
|
||||
// For signing in to Google, append the scope for obtaining the
|
||||
// authenticated user email and profile, as appropriate. This is usually
|
||||
// done by the startSigningIn method, but this method is not called when
|
||||
// exchanging an authentication token for a refresh token.
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
[self addScopeForGoogleUserInfo];
|
||||
#endif
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSString *code = auth.code;
|
||||
if ([code length] > 0) {
|
||||
// exchange the code for a token
|
||||
SEL sel = @selector(auth:finishedWithFetcher:error:);
|
||||
GTMHTTPFetcher *fetcher = [auth beginTokenFetchWithDelegate:self
|
||||
didFinishSelector:sel];
|
||||
if (fetcher == nil) {
|
||||
error = [NSError errorWithDomain:kGTMHTTPFetcherStatusDomain
|
||||
code:-1
|
||||
userInfo:nil];
|
||||
} else {
|
||||
self.pendingFetcher = fetcher;
|
||||
}
|
||||
|
||||
// notify the app so it can put up a post-sign in, pre-token exchange UI
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:kGTMOAuth2UserSignedIn
|
||||
object:self
|
||||
userInfo:nil];
|
||||
} else {
|
||||
// the callback lacked an auth code
|
||||
NSString *errStr = auth.errorString;
|
||||
NSDictionary *userInfo = nil;
|
||||
if ([errStr length] > 0) {
|
||||
userInfo = [NSDictionary dictionaryWithObject:errStr
|
||||
forKey:kGTMOAuth2ErrorMessageKey];
|
||||
}
|
||||
|
||||
error = [NSError errorWithDomain:kGTMOAuth2ErrorDomain
|
||||
code:kGTMOAuth2ErrorAuthorizationFailed
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
[self finishSignInWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)auth:(GTMOAuth2Authentication *)auth
|
||||
finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
error:(NSError *)error {
|
||||
self.pendingFetcher = nil;
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
if (error == nil
|
||||
&& (self.shouldFetchGoogleUserEmail || self.shouldFetchGoogleUserProfile)
|
||||
&& [self.authentication.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) {
|
||||
// fetch the user's information from the Google server
|
||||
[self fetchGoogleUserInfo];
|
||||
} else {
|
||||
// we're not authorizing with Google, so we're done
|
||||
[self finishSignInWithError:error];
|
||||
}
|
||||
#else
|
||||
[self finishSignInWithError:error];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (GTMHTTPFetcher *)userInfoFetcherWithAuth:(GTMOAuth2Authentication *)auth {
|
||||
// create a fetcher for obtaining the user's email or profile
|
||||
NSURL *infoURL = [[self class] googleUserInfoURL];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:infoURL];
|
||||
|
||||
if ([auth respondsToSelector:@selector(userAgent)]) {
|
||||
NSString *userAgent = [auth userAgent];
|
||||
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||
}
|
||||
[request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];
|
||||
|
||||
GTMHTTPFetcher *fetcher;
|
||||
id <GTMHTTPFetcherServiceProtocol> fetcherService = nil;
|
||||
if ([auth respondsToSelector:@selector(fetcherService)]) {
|
||||
fetcherService = auth.fetcherService;
|
||||
};
|
||||
if (fetcherService) {
|
||||
fetcher = [fetcherService fetcherWithRequest:request];
|
||||
} else {
|
||||
fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
|
||||
}
|
||||
fetcher.authorizer = auth;
|
||||
fetcher.retryEnabled = YES;
|
||||
fetcher.maxRetryInterval = 15.0;
|
||||
fetcher.comment = @"user info";
|
||||
return fetcher;
|
||||
}
|
||||
|
||||
- (void)fetchGoogleUserInfo {
|
||||
if (!self.shouldFetchGoogleUserProfile) {
|
||||
// If we only need email and user ID, not the full profile, and we have an
|
||||
// id_token, it may have the email and user ID so we won't need to fetch
|
||||
// them.
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSString *idToken = [auth.parameters objectForKey:@"id_token"];
|
||||
if ([idToken length] > 0) {
|
||||
// The id_token has three dot-delimited parts. The second is the
|
||||
// JSON profile.
|
||||
//
|
||||
// http://www.tbray.org/ongoing/When/201x/2013/04/04/ID-Tokens
|
||||
NSArray *parts = [idToken componentsSeparatedByString:@"."];
|
||||
if ([parts count] == 3) {
|
||||
NSString *part2 = [parts objectAtIndex:1];
|
||||
if ([part2 length] > 0) {
|
||||
NSData *data = [[self class] decodeWebSafeBase64:part2];
|
||||
if ([data length] > 0) {
|
||||
[self updateGoogleUserInfoWithData:data];
|
||||
if ([[auth userID] length] > 0 && [[auth userEmail] length] > 0) {
|
||||
// We obtained user ID and email from the ID token.
|
||||
[self finishSignInWithError:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the email and profile from the userinfo endpoint.
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
GTMHTTPFetcher *fetcher = [[self class] userInfoFetcherWithAuth:auth];
|
||||
[fetcher beginFetchWithDelegate:self
|
||||
didFinishSelector:@selector(infoFetcher:finishedWithData:error:)];
|
||||
|
||||
self.pendingFetcher = fetcher;
|
||||
|
||||
[auth notifyFetchIsRunning:YES
|
||||
fetcher:fetcher
|
||||
type:kGTMOAuth2FetchTypeUserInfo];
|
||||
}
|
||||
|
||||
- (void)infoFetcher:(GTMHTTPFetcher *)fetcher
|
||||
finishedWithData:(NSData *)data
|
||||
error:(NSError *)error {
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
[auth notifyFetchIsRunning:NO
|
||||
fetcher:fetcher
|
||||
type:nil];
|
||||
|
||||
self.pendingFetcher = nil;
|
||||
|
||||
if (error) {
|
||||
#if DEBUG
|
||||
if (data) {
|
||||
NSString *dataStr = [[[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding] autorelease];
|
||||
NSLog(@"infoFetcher error: %@\n%@", error, dataStr);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// We have the authenticated user's info
|
||||
[self updateGoogleUserInfoWithData:data];
|
||||
}
|
||||
[self finishSignInWithError:error];
|
||||
}
|
||||
|
||||
- (void)updateGoogleUserInfoWithData:(NSData *)data {
|
||||
if (!data) return;
|
||||
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSDictionary *profileDict = [[auth class] dictionaryWithJSONData:data];
|
||||
if (profileDict) {
|
||||
// Profile dictionary keys mostly conform to
|
||||
// http://openid.net/specs/openid-connect-messages-1_0.html#StandardClaims
|
||||
|
||||
self.userProfile = profileDict;
|
||||
|
||||
// Save the ID into the auth object
|
||||
NSString *subjectID = [profileDict objectForKey:@"sub"];
|
||||
[auth setUserID:subjectID];
|
||||
|
||||
// Save the email into the auth object
|
||||
NSString *email = [profileDict objectForKey:@"email"];
|
||||
[auth setUserEmail:email];
|
||||
|
||||
// The email_verified key is a boolean NSNumber in the userinfo
|
||||
// endpoint response, but it is a string like "true" in the id_token.
|
||||
// We want to consistently save it as a string of the boolean value,
|
||||
// like @"1".
|
||||
id verified = [profileDict objectForKey:@"email_verified"];
|
||||
if ([verified isKindOfClass:[NSString class]]) {
|
||||
verified = [NSNumber numberWithBool:[verified boolValue]];
|
||||
}
|
||||
|
||||
[auth setUserEmailIsVerified:[verified stringValue]];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
|
||||
- (void)finishSignInWithError:(NSError *)error {
|
||||
[self invokeFinalCallbackWithError:error];
|
||||
}
|
||||
|
||||
// convenience method for making the final call to our delegate
|
||||
- (void)invokeFinalCallbackWithError:(NSError *)error {
|
||||
if (delegate_ && finishedSelector_) {
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
|
||||
NSMethodSignature *sig = [delegate_ methodSignatureForSelector:finishedSelector_];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
|
||||
[invocation setSelector:finishedSelector_];
|
||||
[invocation setTarget:delegate_];
|
||||
[invocation setArgument:&self atIndex:2];
|
||||
[invocation setArgument:&auth atIndex:3];
|
||||
[invocation setArgument:&error atIndex:4];
|
||||
[invocation invoke];
|
||||
}
|
||||
|
||||
// we'll no longer send messages to the delegate
|
||||
//
|
||||
// we want to autorelease it rather than assign to the property in case
|
||||
// the delegate is below us in the call stack
|
||||
[delegate_ autorelease];
|
||||
delegate_ = nil;
|
||||
}
|
||||
|
||||
#pragma mark Reachability monitoring
|
||||
|
||||
static void ReachabilityCallBack(SCNetworkReachabilityRef target,
|
||||
SCNetworkConnectionFlags flags,
|
||||
void *info) {
|
||||
// pass the flags to the signIn object
|
||||
GTMOAuth2SignIn *signIn = (GTMOAuth2SignIn *)info;
|
||||
|
||||
[signIn reachabilityTarget:target
|
||||
changedFlags:flags];
|
||||
}
|
||||
|
||||
- (void)startReachabilityCheck {
|
||||
// the user may set the timeout to 0 to skip the reachability checking
|
||||
// during display of the sign-in page
|
||||
if (networkLossTimeoutInterval_ <= 0.0 || reachabilityRef_ != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create a reachability target from the authorization URL, add our callback,
|
||||
// and schedule it on the run loop so we'll be notified if the network drops
|
||||
NSURL *url = self.authorizationURL;
|
||||
const char* host = [[url host] UTF8String];
|
||||
reachabilityRef_ = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault,
|
||||
host);
|
||||
if (reachabilityRef_) {
|
||||
BOOL isScheduled = NO;
|
||||
SCNetworkReachabilityContext ctx = { 0, self, NULL, NULL, NULL };
|
||||
|
||||
if (SCNetworkReachabilitySetCallback(reachabilityRef_,
|
||||
ReachabilityCallBack, &ctx)) {
|
||||
if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef_,
|
||||
CFRunLoopGetCurrent(),
|
||||
kCFRunLoopDefaultMode)) {
|
||||
isScheduled = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isScheduled) {
|
||||
CFRelease(reachabilityRef_);
|
||||
reachabilityRef_ = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroyUnreachabilityTimer {
|
||||
[networkLossTimer_ invalidate];
|
||||
[networkLossTimer_ autorelease];
|
||||
networkLossTimer_ = nil;
|
||||
}
|
||||
|
||||
- (void)reachabilityTarget:(SCNetworkReachabilityRef)reachabilityRef
|
||||
changedFlags:(SCNetworkConnectionFlags)flags {
|
||||
BOOL isConnected = (flags & kSCNetworkFlagsReachable) != 0
|
||||
&& (flags & kSCNetworkFlagsConnectionRequired) == 0;
|
||||
|
||||
if (isConnected) {
|
||||
// server is again reachable
|
||||
[self destroyUnreachabilityTimer];
|
||||
|
||||
if (hasNotifiedNetworkLoss_) {
|
||||
// tell the user that the network has been found
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:kGTMOAuth2NetworkFound
|
||||
object:self
|
||||
userInfo:nil];
|
||||
hasNotifiedNetworkLoss_ = NO;
|
||||
}
|
||||
} else {
|
||||
// the server has become unreachable; start the timer, if necessary
|
||||
if (networkLossTimer_ == nil
|
||||
&& networkLossTimeoutInterval_ > 0
|
||||
&& !hasNotifiedNetworkLoss_) {
|
||||
SEL sel = @selector(reachabilityTimerFired:);
|
||||
networkLossTimer_ = [[NSTimer scheduledTimerWithTimeInterval:networkLossTimeoutInterval_
|
||||
target:self
|
||||
selector:sel
|
||||
userInfo:nil
|
||||
repeats:NO] retain];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reachabilityTimerFired:(NSTimer *)timer {
|
||||
// the user may call [[notification object] cancelSigningIn] to
|
||||
// dismiss the sign-in
|
||||
if (!hasNotifiedNetworkLoss_) {
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:kGTMOAuth2NetworkLost
|
||||
object:self
|
||||
userInfo:nil];
|
||||
hasNotifiedNetworkLoss_ = YES;
|
||||
}
|
||||
|
||||
[self destroyUnreachabilityTimer];
|
||||
}
|
||||
|
||||
- (void)stopReachabilityCheck {
|
||||
[self destroyUnreachabilityTimer];
|
||||
|
||||
if (reachabilityRef_) {
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef_,
|
||||
CFRunLoopGetCurrent(),
|
||||
kCFRunLoopDefaultMode);
|
||||
SCNetworkReachabilitySetCallback(reachabilityRef_, NULL, NULL);
|
||||
|
||||
CFRelease(reachabilityRef_);
|
||||
reachabilityRef_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Token Revocation
|
||||
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth {
|
||||
if (auth.refreshToken != nil
|
||||
&& auth.canAuthorize
|
||||
&& [auth.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) {
|
||||
|
||||
// create a signed revocation request for this authentication object
|
||||
NSURL *url = [self googleRevocationURL];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSString *token = auth.refreshToken;
|
||||
NSString *encoded = [GTMOAuth2Authentication encodedOAuthValueForString:token];
|
||||
if (encoded != nil) {
|
||||
NSString *body = [@"token=" stringByAppendingString:encoded];
|
||||
|
||||
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[request setHTTPMethod:@"POST"];
|
||||
|
||||
NSString *userAgent = [auth userAgent];
|
||||
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||
|
||||
// there's nothing to be done if revocation succeeds or fails
|
||||
GTMHTTPFetcher *fetcher;
|
||||
id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService;
|
||||
if (fetcherService) {
|
||||
fetcher = [fetcherService fetcherWithRequest:request];
|
||||
} else {
|
||||
fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
|
||||
}
|
||||
fetcher.comment = @"revoke token";
|
||||
|
||||
// Use a completion handler fetch for better debugging, but only if we're
|
||||
// guaranteed that blocks are available in the runtime
|
||||
#if (!TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)) || \
|
||||
(TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000))
|
||||
// Blocks are available
|
||||
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
|
||||
#if DEBUG
|
||||
if (error) {
|
||||
NSString *errStr = [[[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding] autorelease];
|
||||
NSLog(@"revoke error: %@", errStr);
|
||||
}
|
||||
#endif // DEBUG
|
||||
}];
|
||||
#else
|
||||
// Blocks may not be available
|
||||
[fetcher beginFetchWithDelegate:nil didFinishSelector:NULL];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
[auth reset];
|
||||
}
|
||||
|
||||
|
||||
// Based on Cyrus Najmabadi's elegent little encoder and decoder from
|
||||
// http://www.cocoadev.com/index.pl?BaseSixtyFour and on GTLBase64
|
||||
|
||||
+ (NSData *)decodeWebSafeBase64:(NSString *)base64Str {
|
||||
static char decodingTable[128];
|
||||
static BOOL hasInited = NO;
|
||||
|
||||
if (!hasInited) {
|
||||
char webSafeEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
memset(decodingTable, 0, 128);
|
||||
for (unsigned int i = 0; i < sizeof(webSafeEncodingTable); i++) {
|
||||
decodingTable[(unsigned int) webSafeEncodingTable[i]] = (char)i;
|
||||
}
|
||||
hasInited = YES;
|
||||
}
|
||||
|
||||
// The input string should be plain ASCII.
|
||||
const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
if (cString == nil) return nil;
|
||||
|
||||
NSInteger inputLength = (NSInteger)strlen(cString);
|
||||
// Input length is not being restricted to multiples of 4.
|
||||
if (inputLength == 0) return [NSData data];
|
||||
|
||||
while (inputLength > 0 && cString[inputLength - 1] == '=') {
|
||||
inputLength--;
|
||||
}
|
||||
|
||||
NSInteger outputLength = inputLength * 3 / 4;
|
||||
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)outputLength];
|
||||
uint8_t *output = [data mutableBytes];
|
||||
|
||||
NSInteger inputPoint = 0;
|
||||
NSInteger outputPoint = 0;
|
||||
char *table = decodingTable;
|
||||
|
||||
while (inputPoint < inputLength - 1) {
|
||||
int i0 = cString[inputPoint++];
|
||||
int i1 = cString[inputPoint++];
|
||||
int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0
|
||||
int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A';
|
||||
|
||||
output[outputPoint++] = (uint8_t)((table[i0] << 2) | (table[i1] >> 4));
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = (uint8_t)(((table[i1] & 0xF) << 4) | (table[i2] >> 2));
|
||||
}
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = (uint8_t)(((table[i2] & 0x3) << 6) | table[i3]);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
|
||||
@end
|
||||
|
||||
#endif // #if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
|
@ -0,0 +1,377 @@
|
|||
/* Copyright (c) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// GTMOAuth2ViewControllerTouch.h
|
||||
//
|
||||
// This view controller for iPhone handles sign-in via OAuth to Google or
|
||||
// other services.
|
||||
//
|
||||
// This controller is not reusable; create a new instance of this controller
|
||||
// every time the user will sign in.
|
||||
//
|
||||
|
||||
#if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "GTMOAuth2Authentication.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern NSString *const kGTMOAuth2KeychainErrorDomain;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@class GTMOAuth2SignIn;
|
||||
@class GTMOAuth2ViewControllerTouch;
|
||||
|
||||
typedef void (^GTMOAuth2ViewControllerCompletionHandler)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error);
|
||||
|
||||
@interface GTMOAuth2ViewControllerTouch : UIViewController<UINavigationControllerDelegate, UIWebViewDelegate> {
|
||||
@private
|
||||
UIButton *backButton_;
|
||||
UIButton *forwardButton_;
|
||||
UIActivityIndicatorView *initialActivityIndicator_;
|
||||
UIView *navButtonsView_;
|
||||
UIBarButtonItem *rightBarButtonItem_;
|
||||
UIWebView *webView_;
|
||||
|
||||
// The object responsible for the sign-in networking sequence; it holds
|
||||
// onto the authentication object as well.
|
||||
GTMOAuth2SignIn *signIn_;
|
||||
|
||||
// the page request to load when awakeFromNib occurs
|
||||
NSURLRequest *request_;
|
||||
|
||||
// The user we're calling back
|
||||
//
|
||||
// The delegate is retained only until the callback is invoked
|
||||
// or the sign-in is canceled
|
||||
id delegate_;
|
||||
SEL finishedSelector_;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
GTMOAuth2ViewControllerCompletionHandler completionBlock_;
|
||||
|
||||
void (^popViewBlock_)(void);
|
||||
#endif
|
||||
|
||||
NSString *keychainItemName_;
|
||||
CFTypeRef keychainItemAccessibility_;
|
||||
|
||||
// if non-nil, the html string to be displayed immediately upon opening
|
||||
// of the web view
|
||||
NSString *initialHTMLString_;
|
||||
|
||||
// set to 1 or -1 if the user sets the showsInitialActivityIndicator
|
||||
// property
|
||||
int mustShowActivityIndicator_;
|
||||
|
||||
// if non-nil, the URL for which cookies will be deleted when the
|
||||
// browser view is dismissed
|
||||
NSURL *browserCookiesURL_;
|
||||
|
||||
id userData_;
|
||||
NSMutableDictionary *properties_;
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
|
||||
// We delegate the decision to our owning NavigationController (if any).
|
||||
// But, the NavigationController will call us back, and ask us.
|
||||
// BOOL keeps us from infinite looping.
|
||||
BOOL isInsideShouldAutorotateToInterfaceOrientation_;
|
||||
#endif
|
||||
|
||||
// YES, when view first shown in this signIn session.
|
||||
BOOL isViewShown_;
|
||||
|
||||
// YES, after the view has fully transitioned in.
|
||||
BOOL didViewAppear_;
|
||||
|
||||
// YES between sends of start and stop notifications
|
||||
BOOL hasNotifiedWebViewStartedLoading_;
|
||||
|
||||
// To prevent us from calling our delegate's selector more than once.
|
||||
BOOL hasCalledFinished_;
|
||||
|
||||
// Set in a webView callback.
|
||||
BOOL hasDoneFinalRedirect_;
|
||||
|
||||
// Set during the pop initiated by the sign-in object; otherwise,
|
||||
// viewWillDisappear indicates that some external change of the view
|
||||
// has stopped the sign-in.
|
||||
BOOL didDismissSelf_;
|
||||
|
||||
// Work around default cookie policy bug in iOS 7; see comments in viewWillAppear.
|
||||
NSHTTPCookieAcceptPolicy savedCookiePolicy_;
|
||||
}
|
||||
|
||||
// the application and service name to use for saving the auth tokens
|
||||
// to the keychain
|
||||
@property (nonatomic, copy) NSString *keychainItemName;
|
||||
|
||||
// the keychain item accessibility is a system constant for use
|
||||
// with kSecAttrAccessible.
|
||||
//
|
||||
// Since it's a system constant, we do not need to retain it.
|
||||
@property (nonatomic, assign) CFTypeRef keychainItemAccessibility;
|
||||
|
||||
// optional html string displayed immediately upon opening the web view
|
||||
//
|
||||
// This string is visible just until the sign-in web page loads, and
|
||||
// may be used for a "Loading..." type of message or to set the
|
||||
// initial view color
|
||||
@property (nonatomic, copy) NSString *initialHTMLString;
|
||||
|
||||
// an activity indicator shows during initial webview load when no initial HTML
|
||||
// string is specified, but the activity indicator can be forced to be shown
|
||||
// with this property
|
||||
@property (nonatomic, assign) BOOL showsInitialActivityIndicator;
|
||||
|
||||
// the underlying object to hold authentication tokens and authorize http
|
||||
// requests
|
||||
@property (nonatomic, retain, readonly) GTMOAuth2Authentication *authentication;
|
||||
|
||||
// the underlying object which performs the sign-in networking sequence
|
||||
@property (nonatomic, retain, readonly) GTMOAuth2SignIn *signIn;
|
||||
|
||||
// user interface elements
|
||||
@property (nonatomic, retain) IBOutlet UIButton *backButton;
|
||||
@property (nonatomic, retain) IBOutlet UIButton *forwardButton;
|
||||
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *initialActivityIndicator;
|
||||
@property (nonatomic, retain) IBOutlet UIView *navButtonsView;
|
||||
@property (nonatomic, retain) IBOutlet UIBarButtonItem *rightBarButtonItem;
|
||||
@property (nonatomic, retain) IBOutlet UIWebView *webView;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
// An optional block to be called when the view should be popped. If not set,
|
||||
// the view controller will use its navigation controller to pop the view.
|
||||
@property (nonatomic, copy) void (^popViewBlock)(void);
|
||||
#endif
|
||||
|
||||
// the default timeout for an unreachable network during display of the
|
||||
// sign-in page is 30 seconds; set this to 0 to have no timeout
|
||||
@property (nonatomic, assign) NSTimeInterval networkLossTimeoutInterval;
|
||||
|
||||
// if set, cookies are deleted for this URL when the view is hidden
|
||||
//
|
||||
// For Google sign-ins, this is set by default to https://google.com/accounts
|
||||
// but it may be explicitly set to nil to disable clearing of browser cookies
|
||||
@property (nonatomic, retain) NSURL *browserCookiesURL;
|
||||
|
||||
// userData is retained for the convenience of the caller
|
||||
@property (nonatomic, retain) id userData;
|
||||
|
||||
// Stored property values are retained for the convenience of the caller
|
||||
- (void)setProperty:(id)obj forKey:(NSString *)key;
|
||||
- (id)propertyForKey:(NSString *)key;
|
||||
|
||||
@property (nonatomic, retain) NSDictionary *properties;
|
||||
|
||||
// Method for creating a controller to authenticate to Google services
|
||||
//
|
||||
// scope is the requested scope of authorization
|
||||
// (like "http://www.google.com/m8/feeds")
|
||||
//
|
||||
// keychain item name is used for storing the token on the keychain,
|
||||
// keychainItemName should be like "My Application: Google Latitude"
|
||||
// (or set to nil if no persistent keychain storage is desired)
|
||||
//
|
||||
// the delegate is retained only until the finished selector is invoked
|
||||
// or the sign-in is canceled
|
||||
//
|
||||
// If you don't like the default nibName and bundle, you can change them
|
||||
// using the UIViewController properties once you've made one of these.
|
||||
//
|
||||
// finishedSelector is called after authentication completes. It should follow
|
||||
// this signature.
|
||||
//
|
||||
// - (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
|
||||
// finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
// error:(NSError *)error;
|
||||
//
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (id)controllerWithScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
delegate:(id)delegate
|
||||
finishedSelector:(SEL)finishedSelector;
|
||||
|
||||
- (id)initWithScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
delegate:(id)delegate
|
||||
finishedSelector:(SEL)finishedSelector;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
+ (id)controllerWithScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
|
||||
- (id)initWithScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Create a controller for authenticating to non-Google services, taking
|
||||
// explicit endpoint URLs and an authentication object
|
||||
+ (id)controllerWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName // may be nil
|
||||
delegate:(id)delegate
|
||||
finishedSelector:(SEL)finishedSelector;
|
||||
|
||||
// This is the designated initializer
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
delegate:(id)delegate
|
||||
finishedSelector:(SEL)finishedSelector;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
+ (id)controllerWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName // may be nil
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
#endif
|
||||
|
||||
// subclasses may override authNibName to specify a custom name
|
||||
+ (NSString *)authNibName;
|
||||
|
||||
// subclasses may override authNibBundle to specify a custom bundle
|
||||
+ (NSBundle *)authNibBundle;
|
||||
|
||||
// subclasses may override setUpNavigation to provide their own navigation
|
||||
// controls
|
||||
- (void)setUpNavigation;
|
||||
|
||||
// apps may replace the sign-in class with their own subclass of it
|
||||
+ (Class)signInClass;
|
||||
+ (void)setSignInClass:(Class)theClass;
|
||||
|
||||
- (void)cancelSigningIn;
|
||||
|
||||
// revocation of an authorized token from Google
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Keychain
|
||||
//
|
||||
|
||||
// create an authentication object for Google services from the access
|
||||
// token and secret stored in the keychain; if no token is available, return
|
||||
// an unauthorized auth object. OK to pass NULL for the error parameter.
|
||||
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
+ (GTMOAuth2Authentication *)authForGoogleFromKeychainForName:(NSString *)keychainItemName
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
error:(NSError **)error;
|
||||
// Equivalent to calling the method above with a NULL error parameter.
|
||||
+ (GTMOAuth2Authentication *)authForGoogleFromKeychainForName:(NSString *)keychainItemName
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret;
|
||||
#endif
|
||||
|
||||
// add tokens from the keychain, if available, to the authentication object
|
||||
//
|
||||
// returns YES if the authentication object was authorized from the keychain
|
||||
+ (BOOL)authorizeFromKeychainForName:(NSString *)keychainItemName
|
||||
authentication:(GTMOAuth2Authentication *)auth
|
||||
error:(NSError **)error;
|
||||
|
||||
// method for deleting the stored access token and secret, useful for "signing
|
||||
// out"
|
||||
+ (BOOL)removeAuthFromKeychainForName:(NSString *)keychainItemName;
|
||||
|
||||
// method for saving the stored access token and secret
|
||||
//
|
||||
// returns YES if the save was successful. OK to pass NULL for the error
|
||||
// parameter.
|
||||
+ (BOOL)saveParamsToKeychainForName:(NSString *)keychainItemName
|
||||
accessibility:(CFTypeRef)accessibility
|
||||
authentication:(GTMOAuth2Authentication *)auth
|
||||
error:(NSError **)error;
|
||||
|
||||
// older version, defaults to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
||||
+ (BOOL)saveParamsToKeychainForName:(NSString *)keychainItemName
|
||||
authentication:(GTMOAuth2Authentication *)auth;
|
||||
|
||||
@end
|
||||
|
||||
// To function, GTMOAuth2ViewControllerTouch needs a certain amount of access
|
||||
// to the iPhone's keychain. To keep things simple, its keychain access is
|
||||
// broken out into a helper class. We declare it here in case you'd like to use
|
||||
// it too, to store passwords.
|
||||
|
||||
enum {
|
||||
kGTMOAuth2KeychainErrorBadArguments = -1301,
|
||||
kGTMOAuth2KeychainErrorNoPassword = -1302
|
||||
};
|
||||
|
||||
|
||||
@interface GTMOAuth2Keychain : NSObject
|
||||
|
||||
+ (GTMOAuth2Keychain *)defaultKeychain;
|
||||
|
||||
// OK to pass nil for the error parameter.
|
||||
- (NSString *)passwordForService:(NSString *)service
|
||||
account:(NSString *)account
|
||||
error:(NSError **)error;
|
||||
|
||||
// OK to pass nil for the error parameter.
|
||||
- (BOOL)removePasswordForService:(NSString *)service
|
||||
account:(NSString *)account
|
||||
error:(NSError **)error;
|
||||
|
||||
// OK to pass nil for the error parameter.
|
||||
//
|
||||
// accessibility should be one of the constants for kSecAttrAccessible
|
||||
// such as kSecAttrAccessibleWhenUnlocked
|
||||
- (BOOL)setPassword:(NSString *)password
|
||||
forService:(NSString *)service
|
||||
accessibility:(CFTypeRef)accessibility
|
||||
account:(NSString *)account
|
||||
error:(NSError **)error;
|
||||
|
||||
// For unit tests: allow setting a mock object
|
||||
+ (void)setDefaultKeychain:(GTMOAuth2Keychain *)keychain;
|
||||
|
||||
@end
|
||||
|
||||
#endif // TARGET_OS_IPHONE
|
||||
|
||||
#endif // #if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,494 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1024</int>
|
||||
<string key="IBDocument.SystemVersion">12C60</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2840</string>
|
||||
<string key="IBDocument.AppKitVersion">1187.34</string>
|
||||
<string key="IBDocument.HIToolboxVersion">625.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">1926</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIActivityIndicatorView</string>
|
||||
<string>IBUIBarButtonItem</string>
|
||||
<string>IBUIButton</string>
|
||||
<string>IBUINavigationItem</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUIWebView</string>
|
||||
</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">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUINavigationItem" id="1047805472">
|
||||
<string key="IBUITitle">OAuth</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIBarButtonItem" id="961671599">
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIStyle">1</int>
|
||||
</object>
|
||||
<object class="IBUIView" id="808907889">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUIButton" id="453250804">
|
||||
<reference key="NSNextResponder" ref="808907889"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrameSize">{30, 30}</string>
|
||||
<reference key="NSSuperview" ref="808907889"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="981703116"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<string key="IBUITitleShadowOffset">{0, -2}</string>
|
||||
<string key="IBUINormalTitle">◀</string>
|
||||
<object class="NSColor" key="IBUIHighlightedTitleColor" id="193465259">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
<object class="NSColor" key="IBUIDisabledTitleColor">
|
||||
<int key="NSColorSpace">2</int>
|
||||
<bytes key="NSRGB">MC41OTYwNzg0NiAwLjY4NjI3NDUzIDAuOTUyOTQxMjQgMC42MDAwMDAwMgA</bytes>
|
||||
</object>
|
||||
<reference key="IBUINormalTitleColor" ref="193465259"/>
|
||||
<object class="NSColor" key="IBUINormalTitleShadowColor" id="999379443">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MC41AA</bytes>
|
||||
</object>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription" id="621440819">
|
||||
<string key="name">Helvetica-Bold</string>
|
||||
<string key="family">Helvetica</string>
|
||||
<int key="traits">2</int>
|
||||
<double key="pointSize">24</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont" id="530402572">
|
||||
<string key="NSName">Helvetica-Bold</string>
|
||||
<double key="NSSize">24</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUIButton" id="981703116">
|
||||
<reference key="NSNextResponder" ref="808907889"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{30, 0}, {30, 30}}</string>
|
||||
<reference key="NSSuperview" ref="808907889"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<string key="IBUITitleShadowOffset">{0, -2}</string>
|
||||
<string key="IBUINormalTitle">▶</string>
|
||||
<reference key="IBUIHighlightedTitleColor" ref="193465259"/>
|
||||
<object class="NSColor" key="IBUIDisabledTitleColor">
|
||||
<int key="NSColorSpace">2</int>
|
||||
<bytes key="NSRGB">MC41ODQzMTM3NSAwLjY3NDUwOTgyIDAuOTUyOTQxMjQgMC42MDAwMDAwMgA</bytes>
|
||||
</object>
|
||||
<reference key="IBUINormalTitleColor" ref="193465259"/>
|
||||
<reference key="IBUINormalTitleShadowColor" ref="999379443"/>
|
||||
<reference key="IBUIFontDescription" ref="621440819"/>
|
||||
<reference key="IBUIFont" ref="530402572"/>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{60, 30}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="453250804"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MSAwAA</bytes>
|
||||
</object>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
|
||||
<object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
|
||||
<int key="IBUIInterfaceOrientation">3</int>
|
||||
<int key="interfaceOrientation">3</int>
|
||||
</object>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="426018584">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUIWebView" id="663477729">
|
||||
<reference key="NSNextResponder" ref="426018584"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview" ref="426018584"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="268967673"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MSAxIDEAA</bytes>
|
||||
</object>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIDataDetectorTypes">1</int>
|
||||
<bool key="IBUIDetectsPhoneNumbers">YES</bool>
|
||||
</object>
|
||||
<object class="IBUIActivityIndicatorView" id="268967673">
|
||||
<reference key="NSNextResponder" ref="426018584"/>
|
||||
<int key="NSvFlags">301</int>
|
||||
<string key="NSFrame">{{150, 115}, {20, 20}}</string>
|
||||
<reference key="NSSuperview" ref="426018584"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<bool key="IBUIHidesWhenStopped">NO</bool>
|
||||
<bool key="IBUIAnimating">YES</bool>
|
||||
<int key="IBUIStyle">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="663477729"/>
|
||||
<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>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</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">rightBarButtonItem</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="961671599"/>
|
||||
</object>
|
||||
<int key="connectionID">20</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">navButtonsView</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="808907889"/>
|
||||
</object>
|
||||
<int key="connectionID">22</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">backButton</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="453250804"/>
|
||||
</object>
|
||||
<int key="connectionID">25</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">forwardButton</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="981703116"/>
|
||||
</object>
|
||||
<int key="connectionID">26</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="426018584"/>
|
||||
</object>
|
||||
<int key="connectionID">28</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">webView</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="663477729"/>
|
||||
</object>
|
||||
<int key="connectionID">29</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">initialActivityIndicator</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="268967673"/>
|
||||
</object>
|
||||
<int key="connectionID">33</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="663477729"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">9</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">rightBarButtonItem</string>
|
||||
<reference key="source" ref="1047805472"/>
|
||||
<reference key="destination" ref="961671599"/>
|
||||
</object>
|
||||
<int key="connectionID">14</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">goBack</string>
|
||||
<reference key="source" ref="453250804"/>
|
||||
<reference key="destination" ref="663477729"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">18</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">goForward</string>
|
||||
<reference key="source" ref="981703116"/>
|
||||
<reference key="destination" ref="663477729"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">19</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="0">
|
||||
<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="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="1047805472"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">10</int>
|
||||
<reference key="object" ref="961671599"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">15</int>
|
||||
<reference key="object" ref="808907889"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="453250804"/>
|
||||
<reference ref="981703116"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">16</int>
|
||||
<reference key="object" ref="453250804"/>
|
||||
<reference key="parent" ref="808907889"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">17</int>
|
||||
<reference key="object" ref="981703116"/>
|
||||
<reference key="parent" ref="808907889"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">27</int>
|
||||
<reference key="object" ref="426018584"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="663477729"/>
|
||||
<reference ref="268967673"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="663477729"/>
|
||||
<reference key="parent" ref="426018584"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">31</int>
|
||||
<reference key="object" ref="268967673"/>
|
||||
<reference key="parent" ref="426018584"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>10.IBPluginDependency</string>
|
||||
<string>15.IBPluginDependency</string>
|
||||
<string>16.IBPluginDependency</string>
|
||||
<string>17.IBPluginDependency</string>
|
||||
<string>27.IBPluginDependency</string>
|
||||
<string>31.IBPluginDependency</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>GTMOAuth2ViewControllerTouch</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</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>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">33</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">GTMOAuth2ViewControllerTouch</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>backButton</string>
|
||||
<string>forwardButton</string>
|
||||
<string>initialActivityIndicator</string>
|
||||
<string>navButtonsView</string>
|
||||
<string>rightBarButtonItem</string>
|
||||
<string>webView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>UIButton</string>
|
||||
<string>UIButton</string>
|
||||
<string>UIActivityIndicatorView</string>
|
||||
<string>UIView</string>
|
||||
<string>UIBarButtonItem</string>
|
||||
<string>UIWebView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>backButton</string>
|
||||
<string>forwardButton</string>
|
||||
<string>initialActivityIndicator</string>
|
||||
<string>navButtonsView</string>
|
||||
<string>rightBarButtonItem</string>
|
||||
<string>webView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">backButton</string>
|
||||
<string key="candidateClassName">UIButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">forwardButton</string>
|
||||
<string key="candidateClassName">UIButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">initialActivityIndicator</string>
|
||||
<string key="candidateClassName">UIActivityIndicatorView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">navButtonsView</string>
|
||||
<string key="candidateClassName">UIView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">rightBarButtonItem</string>
|
||||
<string key="candidateClassName">UIBarButtonItem</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">webView</string>
|
||||
<string key="candidateClassName">UIWebView</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/GTMOAuth2ViewControllerTouch.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1024" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1536" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">1926</string>
|
||||
</data>
|
||||
</archive>
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// ViewController.h
|
||||
// GoogleAuth
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ViewController : UIViewController
|
||||
@property (strong, nonatomic) IBOutlet UILabel *TokenLabel;
|
||||
|
||||
@end
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// ViewController.m
|
||||
// GoogleAuth
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "GTMOAuth2ViewControllerTouch.h"
|
||||
#import "GTMOAuth2SignIn.h"
|
||||
|
||||
#define ClientID @"GOOGLE_CLIENT_ID"
|
||||
#define ClientSecret @"GOOGLE_CLIENT_SECRET"
|
||||
#define AuthURL @"https://accounts.google.com/o/oauth2/auth"
|
||||
#define TokenURL @"https://accounts.google.com/o/oauth2/token"
|
||||
#define KeychainName @"GoogleKeychainName"
|
||||
#define ServiceProvicer @"InstrumentationApp"
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self loginInToGoogle];
|
||||
}
|
||||
|
||||
- (void)loginInToGoogle
|
||||
{
|
||||
GTMOAuth2Authentication * auth = nil;
|
||||
|
||||
NSURL * tokenURL = [NSURL URLWithString:TokenURL];
|
||||
NSString * redirectURI = @"urn:ietf:wg:oauth:2.0:oob";
|
||||
|
||||
auth = [GTMOAuth2Authentication
|
||||
authenticationWithServiceProvider:ServiceProvicer
|
||||
tokenURL:tokenURL
|
||||
redirectURI:redirectURI
|
||||
clientID:ClientID
|
||||
clientSecret:ClientSecret];
|
||||
|
||||
auth.scope = @"https://www.googleapis.com/auth/plus.me";
|
||||
|
||||
GTMOAuth2ViewControllerTouch * viewController =
|
||||
[[GTMOAuth2ViewControllerTouch alloc]
|
||||
initWithAuthentication:auth
|
||||
authorizationURL:[NSURL URLWithString:AuthURL]
|
||||
keychainItemName:KeychainName
|
||||
delegate:self
|
||||
finishedSelector:@selector(viewController:finishedWithAuth:error:)];
|
||||
|
||||
[self.navigationController pushViewController:viewController animated:YES];
|
||||
}
|
||||
|
||||
- (void)viewController:(GTMOAuth2ViewControllerTouch * )viewController
|
||||
finishedWithAuth:(GTMOAuth2Authentication * )auth
|
||||
error:(NSError * )error
|
||||
{
|
||||
NSString * accessToken = auth.accessToken;
|
||||
|
||||
NSLog(@"auth access token: %@", accessToken);
|
||||
self.TokenLabel.Text = accessToken;
|
||||
|
||||
[self.navigationController popToViewController:self animated:NO];
|
||||
if (error != nil) {
|
||||
|
||||
UIAlertView * alert =
|
||||
[[UIAlertView alloc]
|
||||
initWithTitle:@"Error"
|
||||
message:[error localizedDescription]
|
||||
delegate:nil
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:nil];
|
||||
|
||||
[alert show];
|
||||
} else {
|
||||
|
||||
UIAlertView * alert =
|
||||
[[UIAlertView alloc]
|
||||
initWithTitle:@"Successfully logged in!"
|
||||
message:[error localizedDescription]
|
||||
delegate:nil
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:nil];
|
||||
|
||||
[alert show];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,2 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// main.m
|
||||
// GoogleAuth
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
|
@ -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>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wadewegner.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// GoogleAuthTests.m
|
||||
// GoogleAuthTests
|
||||
//
|
||||
// Created by Wade Wegner on 11/27/13.
|
||||
// Copyright (c) 2013 Wade Wegner. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface GoogleAuthTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation GoogleAuthTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample
|
||||
{
|
||||
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,2 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
Загрузка…
Ссылка в новой задаче