2
0

Compare commits

...

123 Commits

Author SHA1 Message Date
Maarten Billemont
e3963a72ad Press bump. 2013-05-11 20:05:07 -04:00
Maarten Billemont
cefe8d144d Import fix, password type change fix, fancier generator appearance.
[FIXED]     Import of ubiquity changes was using wrong delegate method and MOC.
[FIXED]     Password type change broken when password type causes a class change.
[IMPROVED]  Fancier animation of emergency generator appearance.
2013-05-11 19:43:41 -04:00
Maarten Billemont
076cfb1257 MOC saving improvements, Mac app activation, loading overlay, USM update.
[MOVED]     iOS code from MPAppDelegate_Shared to MPiOSAppDelegate.
[FIXED]     Perform MOC saving in MOC perform blocks.
[FIXED]     Mac: Activate app when showing password window and not active.
[FIXED]     Hide overlay while corruption dialog is up.
[FIXED]     Hide corruption dialog when reloading store.
2013-05-11 08:55:09 -04:00
Maarten Billemont
71e3f44c8c Improved migration, file-based StoreUUID, Mac fixes.
[ADDED]     Migration to file-based StoreUUID.
[IMPROVED]  Cleaner, more modular, migration code.
[FIXED]     Don't hook activation to show password window: too annoying when focus shifts.
[FIXED]     Don't set the active user when just importing ubiquity changes, it causes a log-out.
[ADDED]     Mac: Ability to rebuild iCloud.
[REMOVED]   Mac: wasRunning logic to avoid password window appearance on first activation.
[FIXED]     Mac: Retrieve siteName from main thread.
2013-05-10 11:13:55 -04:00
Maarten Billemont
c36f34346d Output info level logs when sendInfo is enabled to aid in debugging. 2013-05-07 16:16:33 -04:00
Maarten Billemont
cd6b83ffe8 iPhone 5 alignment issue in unlock VC.
[FIXED]     Deselect new user avatar if MOC is unavailable when tapping it.
[FIXED]     Position of avatars & spinner on iPhone 5.
[IMPROVED]  Issue button in review dialog.
2013-05-07 13:25:05 -04:00
Maarten Billemont
d110fd18c1 Started checkpoint and executable name revert.
[ADDED]     "Started" checkpoint that logs some platform environment properties.
[REVERTED]  Executable/app name back to just MasterPassword.
2013-05-07 11:22:01 -04:00
Maarten Billemont
e45b9985c2 Mac: New sites.
[MOVED]     Creation of new elements moved to shared code.
[FIXED]     When switching user, unset active key.
[FIXED]     Synchronize content calculation to avoid race issues while typing.
[ADDED]     Ability to create new sites.
[FIXED]     Unset active element when hitting backspace or escape.
2013-05-07 00:48:48 -04:00
Maarten Billemont
8f4eb6df84 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-03 23:50:57 -04:00
Maarten Billemont
809bd60169 Info.plist fixes.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
[FIXED]     Removed newsstand metadata: this is not a newsstand app.
2013-05-03 11:29:38 -04:00
Maarten Billemont
802c5949da More compatible way of specifying icon files.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
2013-05-03 10:15:27 -04:00
Maarten Billemont
407c5528ee Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
fed3a2bc10 Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
7329353c6c Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
a7c861d1b0 Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
9af8ab3360 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
ddb5328019 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
96d97d95e1 New user on Mac.
[ADDED]     Mac: Support for creating a new user.
2013-05-02 20:40:12 -04:00
Maarten Billemont
ab15694d9a Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
81312e3ff4 Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
5e1e88bdeb Fancier password dialog.
[ADDED]     Mac: Shadows on labels so they're easier to read in regular mode.
[ADDED]     Mac: Some "subtle" bling on the password.
2013-04-30 21:10:52 -04:00
Maarten Billemont
9882bf408c Content generation fix.
[UPDATED]   For safer MOC usage API.
[FIXED]     Actually set the active element so that content is generated.
2013-04-30 20:49:42 -04:00
Maarten Billemont
40f34f3d77 Avoid using object.managedObjectContext - when no strong reference exists to the MOC, it may yield nil.
[FIXED]     Unexpected nil MOCs.
2013-04-30 01:49:53 -04:00
Maarten Billemont
0ee1e176ed Don't use temporary objectIDs for state.
[FIXED]     Make sure we have permanent ObjectIDs before storing them in state.
[FIXED]     MP-14
2013-04-30 00:32:30 -04:00
Maarten Billemont
c73f89e4a1 App versioning update.
[UPDATED]   App versioning: version is now: decimal short commit hash, short version is now tag+commit number.
2013-04-29 21:24:45 -04:00
Maarten Billemont
fe9a1cdbc4 Log Inspector and trace mode.
[ADDED]     Log Inspector, shake on preference screen to open log.
[ADDED]     Trace Mode: Log at trace level.
[FIXED]     Log messages weren't being recorded for inclusion in feedback.
2013-04-29 21:15:14 -04:00
Maarten Billemont
8a4eecd9fa Removed volume button.
[REMOVED]   Volume button in guide - there is no voice-over.
2013-04-28 00:46:08 -04:00
Maarten Billemont
d27a0fdbad Core Data context fixes and migration fixes.
[FIXED]     More careful Core Data threading and context usage.
[FIXED]     iOS bug when migrating, now using USM's copy migration.
[ADDED]     Better handling of store changes while in Main VC and Element List VCs.
2013-04-28 00:35:32 -04:00
Maarten Billemont
07e44a46ae Remove Facebook App ID & add icon to archive. 2013-04-27 17:53:54 -04:00
Maarten Billemont
dfda47bca0 Warn when secret data is unavailable so we notice when it is. 2013-04-27 17:39:31 -04:00
Maarten Billemont
6fb36035c2 TestFlight now uses an "Application Token". 2013-04-27 17:17:51 -04:00
Maarten Billemont
a6e3b83ebb Dumped Google+ SDK.
[UPDATED]   Google+ SDK.
2013-04-27 17:14:05 -04:00
Maarten Billemont
dc3c30a2f7 Localytics update.
[UPDATED]   Localytics update.
[ADDED]     When sendInfo is enabled, set the user identifier on Localytics.
2013-04-27 16:37:32 -04:00
Maarten Billemont
3219fc764f Fixed and updated InAppSettingsKit.
[UPDATED]   InAppSettingsKit
[IMPROVED]  Text in Settings.bundle.
2013-04-27 16:01:31 -04:00
Maarten Billemont
5d5e9395b3 Threading fixes for Mac, spinner fix for iOS.
[UPDATED]   TestFlight.
[FIXED]     Mac: References to MPAppDelegate that should be OS-independant now use MPAppDelegate_Shared.
[FIXED]     Mac: Threading and content UI updates.
[FIXED]     iOS: Spinner was showing when going back to unlock VC.
2013-04-27 00:34:28 -04:00
Maarten Billemont
291b408995 More workspace fixes to avoid iOS/Mac confusion by IDE.
[RENAMED]   MPAppDelegate -> MPiOSAppDelegate for iOS to avoid class name confusion in workspace.
2013-04-24 21:26:04 -04:00
Maarten Billemont
ceb0333fcf Active user switching for for password window.
[RENAMED]   MPAppDelegate -> MPMacAppDelegate for Mac to avoid class name confusion in workspace.
[FIXED]     Window behavior when switching user.
2013-04-24 21:23:53 -04:00
Maarten Billemont
44b4e5430a Password window style.
[ADDED]     Ability to change style of password window.
[FIXED]     Some window activation oddities (WIP).
[UPDATED]   Renamed executable iOS/Mac specific in the hopes of helping with IDE conflicts.
2013-04-24 00:25:51 -04:00
Maarten Billemont
cb7e145e83 Fixed a bunch of OS X issues.
[FIXED]     Don't create a moc when the main moc is unset.
[FIXED]     Load the MPUserEntity into the moc when doing selectUser:
[FIXED]     Remove KVO on activeUserObjectID, isn't used anymore.  Instead, override setActiveUser:
[FIXED]     Don't show the password window on launch.
[FIXED]     Don't force unlock of the key whenever unset - only when the window pops.
[REMOVED]   Migration - this app is not ready for explicit migration, additionally, this block appears to cause a lock-up of the PSC.
2013-04-23 20:38:56 -04:00
Maarten Billemont
35ef2b0789 Icon file restructuring. 2013-04-22 00:57:17 -04:00
Maarten Billemont
e34adae8f0 OS X build fixes. 2013-04-21 17:05:59 -04:00
Maarten Billemont
5137cbf14d Checkpoint for opening emergency generator. 2013-04-21 13:34:33 -04:00
Maarten Billemont
32fb52f48f Update emergencyContentTipContainer in storyboard. 2013-04-20 19:53:54 -04:00
Maarten Billemont
95d5d8b40c Reformat. 2013-04-20 14:11:19 -04:00
Maarten Billemont
c0d57b5561 MPCheckpoint
[UPDATED]   Refactoring of checkpoints.
2013-04-20 13:51:37 -04:00
Maarten Billemont
efcfbe2584 Fixed popup appearance.
[FIXED]     Appearance of popup when copying emergency password.
2013-04-20 12:14:44 -04:00
Maarten Billemont
eeac1d0dd3 Initial page-flip other apps, emergency password copy and marquee hint.
[ADDED]     Initial page-flip animation on opening of other apps VC to make it clear to the user that pages can be flipped.
[ADDED]     Copying of password from emergency generator.
[ADDED]     Marquee animate the bottom tip to also hint about the emergency generator.
2013-04-20 11:44:26 -04:00
Maarten Billemont
ac1358a0ec Emergency generator, action pictograms.
[ADDED]     Emergency Generator!
[ADDED]     Easier method for just using the master password algorithm bare.
[UPDATED]   Pictograms in action popup and centering of text.
2013-04-19 00:43:01 -04:00
Maarten Billemont
c31df49599 activeUser refactor, tool tip hiding and dismiss when logout.
[UPDATED]   Made activeUser access follow same pattern as activeElement which makes it more clear what the thread model is like.
[FIXED]     Save after update of all elements.
[UPDATED]   Tool tips hidden in IB now; makes it less cluttered.
[FIXED]     Dismissing view controllers when logging out.
2013-04-17 22:00:15 -04:00
Maarten Billemont
ee93412dd1 Search & AllSites improvements, sort by recency, rememberLogin setup.
[UPDATED]   Simplified AllSites VC in IB (removed the unused navVC).
[UPDATED]   Outdated sites are now shown in the AllSites VC.
[ADDED]     An update-all-sites button when showing outdated sites in the AllSites VC.
[REMOVED]   Search scopes.
[ADDED]     Sorting elements by recency and usage count now.
[FIXED]     Initial positioning of help container.
[ADDED]     Setup VC for rememberLogin.
2013-04-15 00:04:16 -04:00
Maarten Billemont
7cf2c7f5c6 Setup and guide.
[FIXED]     Setup wasn't showing up on app load.
[FIXED]     More temporary moc fixes and main thread fixes.
[IMPROVED]  Guide now plays an introduction animation.
[FIXED]     Setup iCloud switch is now functional.
2013-04-14 10:26:34 -04:00
Maarten Billemont
5bf8842031 More fixes of temporary moc accesses. 2013-04-13 14:03:50 -04:00
Maarten Billemont
abe874cda3 Temporary moc fix, setup & new guide.
[FIXED]     Pass along temporary mocs, they appear to be stored __weak in the object and we can't rely on them not being nil.
[ADDED]     Setup flow for initially setting the iCloud preference.
[ADDED]     New guide.
[IMPROVED]  Hierarchy and flow of unlock -> main.
2013-04-13 13:40:17 -04:00
Maarten Billemont
036c04f65f Migration cleanup and improvements.
[IMPROVED]  Migration code cleanup.
[FIXED]     When local store migration fails, fall back to opening the old local store if possible.
[FIXED]     Better migration of cloud preferences.
[FIXED]     Better checking of when to perform cloud store migration.
[FIXED]     Always migrate the local store, even when the cloud store is enabled.
[UPDATED]   Removed the loading indicator in favor of a loading overlay.
[UPDATED]   Sorted the file references lexicographically.
2013-04-07 19:43:14 -04:00
Maarten Billemont
418411769d Migration fixes.
[FIXED]     Moved migration into the persistence queue by performing it on willLoadStore.
[FIXED]     Re-enabled cloud after migration.
[UPDATED]   Allow rebuilding the old cloud store if it got deleted locally.
2013-04-06 19:41:20 -04:00
Maarten Billemont
12804984ba Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-04-05 00:33:10 -04:00
Maarten Billemont
de36cf8645 Fixes for new properties in MPAppDelegate_Store
[FIXED]     Properties in categories aren't synthesized.  Using fancy new PearlAssociateObjectProperty from Pearl now to make a fake property.
[FIXED]     Show overlay on UI thread.
[FIXED]     ONLY_ACTIVE_ARCH = NO because weird codesign errors happen on second build with it set to YES.
	modified:   External/Pearl
2013-04-05 00:31:05 -04:00
Maarten Billemont
922230c54e Remove iCloudStoreManager.
[REMOVED]   iCloudStoreManager was replaced by UbiquityStoreManager.
2013-04-04 14:16:33 -04:00
Maarten Billemont
e0e548c611 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-04-04 10:54:07 -04:00
Maarten Billemont
5e40258f54 Updated for new UbiquityStoreManager API.
[UPDATED]   New and improved UbiquityStoreManager with better API.
2013-04-03 19:25:15 -04:00
Maarten Billemont
2f17639eeb Revert "Temporary build fix: Disable iCloudStoreManager integration."
This reverts commit b301d0bdd6.
2013-04-01 22:03:28 -04:00
Maarten Billemont
e22be0f97c Build fixes. 2013-03-30 11:53:26 -04:00
Maarten Billemont
0a394265fa Update Mac project after file restructuring. 2013-03-29 20:24:06 -04:00
Maarten Billemont
9c10a2c4e3 Xcode workspace
[UPDATED]   Crashlytics.
2013-03-29 17:41:22 -04:00
Maarten Billemont
93a672b22f Update build scripts for new paths.
[FIXED]     After relocation, the build scripts need path updates.
2013-03-29 12:10:01 -04:00
Maarten Billemont
b301d0bdd6 Temporary build fix: Disable iCloudStoreManager integration. 2013-03-29 12:03:31 -04:00
Maarten Billemont
1c79545245 Serious houskeeping: Better file structure & preparation for Xcode workspace. 2013-03-29 11:59:47 -04:00
Maarten Billemont
02b323d640 Keep track of some todos. 2013-03-29 09:07:01 -04:00
Maarten Billemont
4b8d30ac28 Initial android artifact.
[ADDED]     Added initial stub for an android MP app.
2013-03-29 09:05:15 -04:00
Maarten Billemont
cd475580ff iCloudStoreManager is now UbiquityStoreManager 2013-03-29 09:05:03 -04:00
Maarten Billemont
f937792fc2 Typo correction in site. 2013-03-28 10:19:30 -04:00
Maarten Billemont
31d4d5b6c6 Extract common code from SearchVC and AllVC.
[ADDED]     A more generic element listing controller, now used by the
            search controller and all elements listing controller.
[IMPROVED]  Improved change detection and UI handling in the element
            listing controllers.
[FIXED]     Bug with previewing generated password types for
            non-generated elements.
2013-02-10 15:28:58 -05:00
Maarten Billemont
d7d91d13c6 UI updates: site search & type change
[ADDED]     Display the password type when searching for sites.
[ADDED]     Indicate the strength of a password type by time to crack.
[ADDED]     Display a password prediction below each password type on
            the type selection screen.
[MOVED]     Moved the Short type below the Basic type because it's less
            secure.
[FIXED]     Some font regression bugs.
2013-02-08 18:11:24 -05:00
Maarten Billemont
16a7b87d2a Update content font to Source Code Pro.
[UPDATE]    Font of element content and loginName to Source Code Pro for
            improved legibility and distinguishment between O and 0.
[REMOVED]   Unused fonts from the bundle to save space.
2013-02-02 14:17:35 -05:00
Maarten Billemont
21f1e7ee49 New element fix and statusbar experimentation.
[FIXED]     Set lastUsed when creating a new site since elements can't
            be saved without that value set.
[UPDATED]   Configuration for tinting of status bar.
            Doesn't work yet with the custom navbar container image:
            Should check if last row of that image's pixels isn't too
            dark.  iOS 6 apparently averages it for the tint color.
2013-02-02 01:38:11 -05:00
Maarten Billemont
ad8317a7a0 All sites add button.
[ADDED]     An add site button in the all sites VC.
2013-02-02 00:45:30 -05:00
Maarten Billemont
820be14845 Add missing dependencies to updateDependencies. 2013-02-01 16:45:35 -05:00
Maarten Billemont
b7d3b2d02c Ignore IDE preferences of Java implementation. 2013-02-01 12:54:57 -05:00
Maarten Billemont
a710765336 Bump Java dependencies to release.
[UPDATED]   Java: property-list to 2.0.0
2013-02-01 12:53:17 -05:00
Maarten Billemont
9a68cbf533 Listing all sites now with bookmark button and modal VC.
[ADDED]     Modal VC to show all sites.
[UPDATED]   All sites button on search bar now uses bookmark button.
[REMOVED]   Query string hack for search results button.
2013-02-01 01:13:45 -05:00
Maarten Billemont
2bb0e2e3ef Icon update.
[UPDATED]   Icon graphics updated.
2013-01-31 20:58:27 -05:00
Maarten Billemont
17c47269a3 Startup UI improvements.
[IMPROVED]  Fade-in effect when opening Master Password.
[IMPROVED]  Shade of circular shadow fixed between launch image and
            background image.
2013-01-31 18:58:56 -05:00
Maarten Billemont
6c23134e47 Update Google+ integration.
[UPDATED]   Google+ SDK to 1.1.0.
2013-01-31 16:33:46 -05:00
Maarten Billemont
cc015ada1b Delete stale reference to facebook-ios-sdk
[REMOVED]   Stale reference to facebook-ios-sdk submodule.
2013-01-31 12:29:24 -05:00
Maarten Billemont
acd52e8ef6 Bump Pearl and TestFlight for iOS 6 fixes.
[UPDATED]   Pearl for iOS 6 compilation fixes.
[UPDATED]   TestFlight for close_file bugfix.
2013-01-31 12:25:17 -05:00
Maarten Billemont
f2ee139db6 Social update, CoreData overhaul & iOS6/rotation fixes.
[REMOVED]   Facebook SDK.
[ADDED]     Social framework integration for Twitter & Facebook.
[MOVED]     User migration warning state moved into MainVC, out of
            data model.
[UPDATED]   Major overhaul of Core Data integration.  Multiple contexts
            and making sure we're on the right thread and the right
            context even for read access.
[FIXED]     Some iOS 6 deprecation fixes.
[FIXED]     Some VC rotation issues.
2013-01-31 00:42:32 -05:00
Maarten Billemont
725da285da Minor code improvement.
[FIXED]     Some minor code fixes thanks to inspections.
[FIXED]     Some iOS6 deprecation issues.
[IMPROVED]  Cleanup with regards to store migration.
2013-01-27 16:27:49 -05:00
Maarten Billemont
1b3f5f5d25 Added a few missing resources.
[ADDED]     Mac: Missing menu icon.
[UPDATED]   Sketch source file for iOS app icon and Mac menu icon.
2013-01-27 01:02:41 -05:00
Maarten Billemont
ecd03ecf42 Update of iOS code for updated API of UbiquityStoreManager.
[UPDATED]   UbiquityStoreManager's new API uses cloudEnabled instead of iCloudEnabled.
2013-01-27 00:54:54 -05:00
Maarten Billemont
d5bffd86d6 Mac fixes and improvements to usability.
[FIXED]     Mac: Locking shouldn't unset the active user.
[IMPROVED]  Mac: Behavior of auto-completing site-name field improved.
[ADDED]     Mac: Alert when MP is incorrect when unlocking.
2013-01-26 22:12:34 -05:00
Maarten Billemont
b07298e203 Fixed migration of old store to new store + don't hold references to CoreData objects.
[FIXED]     Working migration of old store to new store.
[FIXED]     We shouldn't be holding references to CoreData objects anywhere.
            In that light, the user NSMenuItems have been fixed.
2013-01-25 01:05:31 -05:00
Maarten Billemont
4c19a29897 Mac support for user handling and iCloud improvements.
[MOVED]     Extract user migration out of iOS specific codebase.
[UPDATED]   iCloud persistence manager.
[ADDED]     Mac: Hotkey for signing the user out.
[IMPROVED]  Mac: Menu item handling and usability.
2013-01-17 00:37:20 -05:00
Maarten Billemont
32f870406c Mac UI fixes.
[FIXED]     Behavior of the Mac menu item and appearance of the password
            window.
[ADDED]     Disabling menu items while not usable and explaining
            disabled items with tooltips.
2012-11-01 10:55:11 -04:00
Maarten Billemont
05ab38b998 Facebook updates + Mac fixes.
[UPDATED]   Facebook integration bumped for iOS 6.
[FIXED]     Bringing Mac version back up to date.  Compiles again and
            runs with UI bugs.
[ADDED]     Mac: User selection.
2012-10-30 22:54:34 -04:00
Maarten Billemont
678545cc26 Make parent pom resolvable.
[FIXED]     Java: Make the parent POM resolvable for people that don't
            have the snapshot version of it.
2012-10-23 09:21:33 -04:00
Maarten Billemont
4c3e0f0c97 Site updates.
[ADDED]     Smart App Banner added to site.
[UPDATED]   Available-on-App-Store resource updated.
2012-10-09 09:58:44 +02:00
Maarten Billemont
a8752b5f28 Disable TestFlight's feedback dialog.
[REMOVED]   TestFlight's feedback dialog.  It's ugly and it doesn't
            allow log sending.
2012-09-23 17:38:05 +02:00
Maarten Billemont
f75f5c1b30 Signing profile bump. 2012-09-22 17:48:35 +02:00
Maarten Billemont
735a75df92 News file referenced by the new version. 2012-09-22 17:38:05 +02:00
Maarten Billemont
d8414aaab9 Fix the URL of the news page to point to the web. 2012-09-22 10:23:21 +02:00
Maarten Billemont
02a5d48ce4 Added a news view.
[ADDED]     A news view on the unlock screen.
2012-09-22 10:14:41 +02:00
Maarten Billemont
cdee54a0f7 TestFlight update to 1.1 2012-09-22 08:53:55 +02:00
Maarten Billemont
b1f0f70849 Localytics SDK update because of startup issue. 2012-09-21 19:42:18 +02:00
Maarten Billemont
850978cbe3 Fixed bug with scroll view in iOS5.
[FIXED]     On iOS5, the app crashed because gesture recognizers of a
            scrollview were being replaced.  Now properly adding the
            desired gesture recognizer to the scroll view preserving the
            existing gesture recognizers.
2012-09-21 16:45:57 +02:00
Maarten Billemont
e8c00296bd TestFligt identifier + Localytics crash.
[IMPROVED]  Use correct device identifier for TestFlight depending on
            whether we're in AdHoc mode or not.
[FIXED]     Crash when sending nil config values to Localytics.
2012-09-21 10:31:48 +02:00
Maarten Billemont
52b8033c37 Fixed issue with logs in feedback message.
[FIXED]     Including logs in the feedback message caused failure to
            parse attachments.
2012-09-20 21:37:58 +02:00
Maarten Billemont
6f2bc83806 Revert the renameID change to see if it causes model incompatibilties. 2012-09-20 21:19:44 +02:00
Maarten Billemont
2a48c9d272 Fixed some rare crashes.
[FIXED]     Crash for users with no name.
[FIXED]     Crash when copying an element with no content.
2012-09-20 21:16:34 +02:00
Maarten Billemont
27d0373a6e Add TestFlight back. 2012-09-19 23:52:23 +02:00
Maarten Billemont
96b50f7ef0 Not ready yet for ARMv7s.
[REVERTED]  Still too many of our dependant libs have no ARMv7s symbols.
2012-09-19 23:46:39 +02:00
Maarten Billemont
dc7ff5f668 Bump for ARMv7s Pearl libs. 2012-09-19 23:43:15 +02:00
Maarten Billemont
0c9c9737d9 Only show TestFlight feedback in Adhoc mode. 2012-09-19 23:34:17 +02:00
Maarten Billemont
8ef099d707 Signing configuration update. 2012-09-19 23:31:46 +02:00
Maarten Billemont
6da15306b0 Work-around for iOS 6 bug.
[FIXED]     iOS 6 SDK seems to crash on iOS 5 devices when doing
            scrollEnabled.
2012-09-19 23:29:21 +02:00
Maarten Billemont
699d0869fc ARMv7s
[UPDATED]   Project configuration update for ARMv7s support.
2012-09-19 22:11:16 +02:00
Maarten Billemont
83efa853fc Binary libraries only support armv7.
[FIXED]     Crashlytics only supports armv7 so force armv7 for now.
2012-09-13 00:48:45 +02:00
Maarten Billemont
75de4b443f iPhone 5 compatibility.
[ADDED]     Taller iPhone 5-size launch image.
[FIXED]     Missing PSC in MOC.
[IMPROVED]  Slower fade-in of unlock UI.
[FIXED]     Properly set enableHTTPS in Localytics.
2012-09-13 00:38:15 +02:00
Maarten Billemont
42c7fb446e Localytics project configuration update. 2012-09-12 16:07:36 +02:00
Maarten Billemont
bce6b96417 Tag screens in Localytics + email fix + psc fix
[FIXED]     Sending email with no recipient caused a crash.
[FIXED]     Duplicate persistence coordinator.
[UPDATED]   Crashlytics and Localytics SDKs.
[UPDATED]   Don't continue the Localytics session when device locked.
[UPDATED]   Put Localytics communication on HTTPS for confidentiality.
[ADDED]     Tagging screens in Localytics.
2012-09-12 16:02:02 +02:00
Maarten Billemont
6f82cf7f15 Fixed crashes related to over-released gesture recognizers.
[FIXED]     Memory warnings caused Master Password to crash due to
            gesture recognizers and an iOS 5 bug.
2012-09-07 23:55:12 +02:00
Maarten Billemont
fac419dd94 Fixes related to review feedback. 2012-09-02 21:16:16 +02:00
Maarten Billemont
c03d547ad8 Font improvements and copy-login fix.
[FIXED]     Login name copies content instead of login name.
[IMPROVED]  Font of password and login name improved for better
            differentiation between capital and lower-case letters.
2012-09-02 13:14:09 +02:00
Maarten Billemont
e2bf8cefa2 Migration of saved passwords.
[ADDED]     Migrate saved passwords when master password changes.
[IMPROVED]  UI improvements to apps.
2012-09-01 22:14:57 +02:00
1193 changed files with 33022 additions and 23807 deletions

10
.gitignore vendored
View File

@@ -2,6 +2,7 @@
.DS_Store .DS_Store
# IntelliJ # IntelliJ
/MasterPassword/Java/.idea
/.idea/* /.idea/*
!/.idea/encodings.xml !/.idea/encodings.xml
!/.idea/inspectionProfiles !/.idea/inspectionProfiles
@@ -12,13 +13,8 @@
/*.iws /*.iws
# Xcode IDE # Xcode IDE
/*.xcodeproj/* xcuserdata/
!/*.xcodeproj/*.pbxproj /DerivedData/
!/*.xcodeproj/xcshareddata
!/*.xcodeproj/xcshareddata/*
!/*.xcodeproj/project.xcworkspace
!/*.xcodeproj/project.xcworkspace/*
/*.xcodeproj/project.xcworkspace/xcuserdata
# Media # Media
Press/Background.png Press/Background.png

12
.gitmodules vendored
View File

@@ -4,12 +4,12 @@
[submodule "External/InAppSettingsKit"] [submodule "External/InAppSettingsKit"]
path = External/InAppSettingsKit path = External/InAppSettingsKit
url = git://github.com/futuretap/InAppSettingsKit.git url = git://github.com/futuretap/InAppSettingsKit.git
[submodule "External/iCloudStoreManager"]
path = External/iCloudStoreManager
url = git://github.com/lhunath/iCloudStoreManager.git
[submodule "External/FontReplacer"] [submodule "External/FontReplacer"]
path = External/FontReplacer path = External/FontReplacer
url = git://github.com/0xced/FontReplacer.git url = git://github.com/0xced/FontReplacer.git
[submodule "External/facebook-ios-sdk"] [submodule "Press"]
path = External/facebook-ios-sdk path = Press
url = https://github.com/facebook/facebook-ios-sdk url = ../Press
[submodule "External/UbiquityStoreManager"]
path = External/UbiquityStoreManager
url = git@github.com:lhunath/UbiquityStoreManager.git

View File

@@ -3,9 +3,13 @@
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<option name="myLocal" value="false" /> <option name="myLocal" value="false" />
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
</profile> </profile>
</component> </component>

View File

@@ -1 +0,0 @@
../../../run

View File

@@ -1,15 +0,0 @@
#!/usr/bin/ruby
#
# WARNING: DO NOT MODIFY THIS FILE.
#
# Crashlytics
# Crashlytics Version: 1.0.0.1
#
# Copyright Crashlytics, Inc. 2012. All rights reserved.
#
require 'pathname'
path = Pathname.new(__FILE__).parent
`#{path}/../../../run`

Binary file not shown.

Binary file not shown.

View File

@@ -2,17 +2,17 @@
// Crashlytics.h // Crashlytics.h
// Crashlytics // Crashlytics
// //
// Copyright 2012 Crashlytics, Inc. All rights reserved. // Copyright 2013 Crashlytics, Inc. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
/** /**
* *
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are * The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and * sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro * line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog. * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only. * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
* *
* Example output: * Example output:
@@ -26,18 +26,18 @@
* *
**/ **/
#ifdef DEBUG #ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) #define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else #else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) #define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif #endif
/** /**
* *
* Add logging that will be sent with your crash data. This logging will not show up in the system.log * Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard. * and will only be visible in your Crashlytics dashboard.
* *
**/ **/
OBJC_EXTERN void CLSLog(NSString *format, ...); OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
/** /**
* *
@@ -45,22 +45,11 @@ OBJC_EXTERN void CLSLog(NSString *format, ...);
* and your Crashlytics dashboard. It is not recommended for Release builds. * and your Crashlytics dashboard. It is not recommended for Release builds.
* *
**/ **/
OBJC_EXTERN void CLSNSLog(NSString *format, ...); OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
@protocol CrashlyticsDelegate; @protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject { @interface Crashlytics : NSObject
@private
NSString *_apiKey;
NSString *_dataDirectory;
NSString *_bundleIdentifier;
BOOL _installed;
NSMutableDictionary *_customAttributes;
id _user;
NSInteger _sendButtonIndex;
NSInteger _alwaysSendButtonIndex;
NSObject <CrashlyticsDelegate> *_delegate;
}
@property (nonatomic, readonly, copy) NSString *apiKey; @property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version; @property (nonatomic, readonly, copy) NSString *version;
@@ -73,7 +62,7 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
* The recommended way to install Crashlytics into your application is to place a call * The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method. * to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
* *
* This delay defaults to 1 second in order to generally give the application time to * This delay defaults to 1 second in order to generally give the application time to
* fully finish launching. * fully finish launching.
* *
**/ **/
@@ -105,21 +94,21 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
/** /**
* *
* Many of our customers have requested the ability to tie crashes to specific end-users of their * Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach * application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within * out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy. * the Crashlytics UI - but please be mindful of your end-user's privacy.
* *
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record * We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a * in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you. * third-party observer but can be indexed and queried by you.
* *
* Optionally, you may also specify the end-user's name or username, as well as email address if you * Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers. * do not have a system that works well with obscured identifiers.
* *
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not * Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user * disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy * contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern. * policy. Data privacy is of our utmost concern.
* *
**/ **/
@@ -148,10 +137,55 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
@end @end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
@property (nonatomic, readonly) NSString *identifier;
/**
* Returns the custom key value data for the crash report.
**/
@property (nonatomic, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the application crashed at.
**/
@property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end
/** /**
* *
* The CrashlyticsDelegate protocol provides a mechanism for your application to take * The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make * action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly, * use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods. * or through the convenience startWithAPIKey:delegate:... methods.
* *
@@ -161,7 +195,7 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
/** /**
* *
* Called once a Crashlytics instance has determined that the last execution of the * Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting * application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the * process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked. * startWithAPIKey:... calls, this will take at least that long to be invoked.
@@ -169,4 +203,15 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
**/ **/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics; - (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end @end

View File

@@ -0,0 +1,30 @@
<?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>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.crashlytics.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.9</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>0200.09.00</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>
<string>4.0</string>
</dict>
</plist>

BIN
External/Crashlytics.framework/run vendored Executable file

Binary file not shown.

21
External/Localytics/LICENSE vendored Executable file
View File

@@ -0,0 +1,21 @@
Copyright (c) 2009, Char Software, Inc. d/b/a Localytics
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Neither the name of Char Software, Inc., Localytics nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY CHAR SOFTWARE, INC. D/B/A LOCALYTICS ''AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL CHAR SOFTWARE, INC. D/B/A LOCALYTICS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,57 +1,74 @@
// //
// LocalyticsDatabase.h // LocalyticsDatabase.h
// LocalyticsDemo // Copyright (C) 2013 Char Software Inc., DBA Localytics
// //
// Created by jkaufman on 5/26/11. // This code is provided under the Localytics Modified BSD License.
// Copyright 2011 Localytics. All rights reserved. // A copy of this license has been distributed in a file called LICENSE
// // with this source code.
//
#import <Foundation/Foundation.h> // Please visit www.localytics.com for more information.
#import <sqlite3.h>
#import <Foundation/Foundation.h>
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes #import <sqlite3.h>
#define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
@interface LocalyticsDatabase : NSObject { #define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
sqlite3 *_databaseConnection;
} @interface LocalyticsDatabase : NSObject {
sqlite3 *_databaseConnection;
+ (LocalyticsDatabase *)sharedLocalyticsDatabase; }
- (NSUInteger)databaseSize; - (unsigned long long)databaseSize;
- (int)eventCount; - (int)eventCount;
- (NSTimeInterval)createdTimestamp; - (NSTimeInterval)createdTimestamp;
- (BOOL)beginTransaction:(NSString *)name; - (BOOL)beginTransaction:(NSString *)name;
- (BOOL)releaseTransaction:(NSString *)name; - (BOOL)releaseTransaction:(NSString *)name;
- (BOOL)rollbackTransaction:(NSString *)name; - (BOOL)rollbackTransaction:(NSString *)name;
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber; - (BOOL)incrementLastUploadNumber:(int *)uploadNumber;
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber; - (BOOL)incrementLastSessionNumber:(int *)sessionNumber;
- (BOOL)addEventWithBlobString:(NSString *)blob; - (BOOL)addEventWithBlobString:(NSString *)blob;
- (BOOL)addCloseEventWithBlobString:(NSString *)blob; - (BOOL)addCloseEventWithBlobString:(NSString *)blob;
- (BOOL)addFlowEventWithBlobString:(NSString *)blob; - (BOOL)queueCloseEventWithBlobString:(NSString *)blob;
- (BOOL)removeLastCloseAndFlowEvents; - (NSString *)dequeueCloseEventBlobString;
- (BOOL)addFlowEventWithBlobString:(NSString *)blob;
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId; - (BOOL)removeLastCloseAndFlowEvents;
- (int)unstagedEventCount;
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId; - (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
- (BOOL)updateAppKey:(NSString *)appKey; - (int)unstagedEventCount;
- (NSString *)uploadBlobString; - (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
- (BOOL)deleteUploadedData; - (BOOL)updateAppKey:(NSString *)appKey;
- (BOOL)resetAnalyticsData; - (NSString *)uploadBlobString;
- (BOOL)vacuumIfRequired; - (BOOL)deleteUploadedData;
- (BOOL)resetAnalyticsData;
- (NSTimeInterval)lastSessionStartTimestamp; - (BOOL)vacuumIfRequired;
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
- (NSTimeInterval)lastSessionStartTimestamp;
- (BOOL)isOptedOut; - (BOOL)setLastSessionStartTimestamp:(NSTimeInterval)timestamp;
- (BOOL)setOptedOut:(BOOL)optOut;
- (NSString *)installId; - (BOOL)isOptedOut;
- (NSString *)appKey; // Most recent app key-- may not be that used to open the session. - (BOOL)setOptedOut:(BOOL)optOut;
- (NSString *)installId;
- (NSString *)customDimension:(int)dimension; - (NSString *)appKey; // Most recent app key-- may not be that used to open the session.
- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
- (NSString *)customDimension:(int)dimension;
@end - (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
- (BOOL)setValueForIdentifier:(NSString *)identifierName value:(NSString *)value;
- (NSString *)valueForIdentifier:(NSString *)identifierName;
- (BOOL)deleteIdentifer:(NSString *)identifierName;
- (NSDictionary *)identifiers;
- (BOOL)setFacebookAttribution:(NSString *)fbAttribution;
- (NSString *)facebookAttributionFromDb;
- (NSString *)facebookAttributionFromPasteboard;
- (NSInteger)safeIntegerValueFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSString *)safeStringValueFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSDictionary *)safeDictionaryFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSArray *)safeListFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
@end

1357
External/Localytics/LocalyticsDatabase.m vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
// LocalyticsSession+Private.h
// Copyright (C) 2013 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import "LocalyticsSession.h"
#import "LocalyticsUploader.h"
#import "LocalyticsDatabase.h"
#define CLIENT_VERSION_PREFIX @"iOS"
#define LOCALYTICS_LOGGING_ENABLED [[LocalyticsSession shared] loggingEnabled]
#define LocalyticsLog(message, ...)if([[LocalyticsSession shared] loggingEnabled]) \
[LocalyticsSession logMessage:[NSString stringWithFormat:@"%s:\n + " message "\n\n", __PRETTY_FUNCTION__, ##__VA_ARGS__]]
@interface LocalyticsSession()
{
BOOL _hasInitialized; // Whether or not the session object has been initialized.
BOOL _isSessionOpen; // Whether or not this session has been opened.
float _sessionTimeoutInterval; // If an App stays in the background for more
// than this many seconds, start a new session
// when it returns to foreground.
@private
#pragma mark Member Variables
dispatch_queue_t _queue; // Queue of Localytics block objects.
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
NSString *_sessionUUID; // Unique identifier for this session.
NSString *_applicationKey; // Unique identifier for the instrumented application
NSString *_facebookAttribution; // Facebook attribution cookie
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session.
NSDate *_sessionResumeTime; // Time session was started or resumed.
NSDate *_sessionCloseTime; // Time session was closed.
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this
// session that have NOT been staged for upload.
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged
// for upload.
NSMutableString *_screens; // Comma-delimited list of screens tagged during this session.
NSTimeInterval _sessionActiveDuration; // Duration that session open.
BOOL _sessionHasBeenOpen; // Whether or not this session has ever been open.
BOOL _delaySession; // Whether or not the server should delay processing on this upload
LocalyticsDatabase *_db; // Localytics database reference
LocalyticsUploader *_uploader; // Localytics uploader reference
}
@property (nonatomic, retain) NSString *applicationKey;
@property (nonatomic, retain) NSString *facebookAttribution;
@property (nonatomic,readonly) dispatch_queue_t queue;
@property (nonatomic,readonly) dispatch_group_t criticalGroup;
@property (atomic) BOOL isSessionOpen;
@property (atomic) BOOL hasInitialized;
@property (nonatomic, retain) NSString *sessionUUID;
@property (nonatomic, assign) NSTimeInterval lastSessionStartTimestamp;
@property (nonatomic, retain) NSDate *sessionResumeTime;
@property (nonatomic, retain) NSDate *sessionCloseTime;
@property (nonatomic, retain) NSMutableString *unstagedFlowEvents;
@property (nonatomic, retain) NSMutableString *stagedFlowEvents;
@property (nonatomic, retain) NSMutableString *screens;
@property (nonatomic, assign) NSTimeInterval sessionActiveDuration;
@property (nonatomic, assign) BOOL sessionHasBeenOpen;
@property (nonatomic, assign) BOOL delaySession;
@property (nonatomic, assign) NSInteger sessionNumber;
// Private methods.
+ (id)allocFactory;
- (void)reopenPreviousSession;
- (void)addFlowEventWithName:(NSString *)name type:(NSString *)eventType;
- (void)addScreenWithName:(NSString *)name;
- (NSString *)blobHeaderStringWithSequenceNumber:(int)nextSequenceNumber;
- (BOOL)ll_isOptedIn;
- (BOOL)createOptEvent:(BOOL)optState;
- (BOOL)saveApplicationFlowAndRemoveOnResume:(BOOL)removeOnResume;
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue;
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue first:(BOOL)firstAttribute;
- (void)uploadCallback:(NSDictionary*)info;
+ (BOOL)appKeyIsValid:(NSString *)appKey;
- (void)ll_open;
- (LocalyticsDatabase *)db;
- (LocalyticsUploader *)uploader;
- (BOOL)uploadIsNeeded;
// Datapoint methods.
- (NSString *)customDimensions;
- (NSString *)locationDimensions;
- (NSString *)hashString:(NSString *)input;
- (NSString *)randomUUID;
- (NSString *)escapeString:(NSString *)input;
- (NSString *)installationId;
- (NSString *)appVersion;
- (NSTimeInterval)currentTimestamp;
- (BOOL)isDeviceJailbroken;
- (NSString *)deviceModel;
- (NSString *)modelSizeString;
- (double)availableMemory;
- (NSString *)advertisingIdentifier;
- (NSString *)uniqueDeviceIdentifier;
@end

View File

@@ -1,216 +1,303 @@
// LocalyticsSession.h // LocalyticsSession.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics // Copyright (C) 2013 Char Software Inc., DBA Localytics
// //
// This code is provided under the Localytics Modified BSD License. // This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE // A copy of this license has been distributed in a file called LICENSE
// with this source code. // with this source code.
// //
// Please visit www.localytics.com for more information. // Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
// Set this to true to enable localytics traces (useful for debugging)
#define DO_LOCALYTICS_LOGGING false #define CLIENT_VERSION @"2.17.3"
#define MARKETING_PLATFORM
/*!
@class LocalyticsSession /*!
@discussion The class which manages creating, collecting, & uploading a Localytics session. @class LocalyticsSession
Please see the following guides for information on how to best use this @discussion The class which manages creating, collecting, & uploading a Localytics session.
library, sample code, and other useful information: Please see the following guides for information on how to best use this
<ul> library, sample code, and other useful information:
<li><a href="http://wiki.localytics.com/index.php?title=Developer's_Integration_Guide">Main Developer's Integration Guide</a></li> <ul>
</ul> <li><a href="http://wiki.localytics.com/index.php?title=Developer's_Integration_Guide">
Main Developer's Integration Guide</a></li>
<strong>Best Practices</strong> </ul>
<ul>
<li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li> <strong>Best Practices</strong>
<li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the <ul>
upload has time to complete and it all happens before your users have a <li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li>
chance to begin any data intensive actions of their own.</li> <li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the
<li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li> upload has time to complete and it all happens before your users have a
<li>Resume the session in applicationWillEnterForeground.</li> chance to begin any data intensive actions of their own.</li>
<li>Do not call any Localytics functions inside a loop. Instead, calls <li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li>
such as <code>tagEvent</code> should follow user actions. This limits the <li>Resume the session in applicationWillEnterForeground.</li>
amount of data which is stored and uploaded.</li> <li>Do not call any Localytics functions inside a loop. Instead, calls
<li>Do not use multiple LocalticsSession objects to upload data with such as <code>tagEvent</code> should follow user actions. This limits the
multiple application keys. This can cause invalid state.</li> amount of data which is stored and uploaded.</li>
</ul> <li>Do not use multiple LocalticsSession objects to upload data with
multiple application keys. This can cause invalid state.</li>
@author Localytics </ul>
*/
@interface LocalyticsSession : NSObject { @author Localytics
*/
BOOL _hasInitialized; // Whether or not the session object has been initialized.
BOOL _isSessionOpen; // Whether or not this session has been opened. // Forward declaration
float _backgroundSessionTimeout; // If an App stays in the background for more @protocol LocalyticsSessionDelegate;
// than this many seconds, start a new session
// when it returns to foreground. @interface LocalyticsSession : NSObject
@private
#pragma mark Member Variables
dispatch_queue_t _queue; // Queue of Localytics block objects. + (void)logMessage:(NSString *)message;
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
NSString *_sessionUUID; // Unique identifier for this session. /*!
NSString *_applicationKey; // Unique identifier for the instrumented application @property enableHTTPS
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session. @abstract (Optional) Determines whether or not HTTPS is used when calling the Localytics
NSDate *_sessionResumeTime; // Time session was started or resumed. post URL. The default is NO.
NSDate *_sessionCloseTime; // Time session was closed. */
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this @property (nonatomic, assign) BOOL enableHTTPS;
// session that have NOT been staged for upload.
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged /*!
// for upload. @property loggingEnabled
NSMutableString *_screens; // Comma-delimited list of screens tagged during this session. @abstract (Optional) Determines whether or Localytics debugging information is shown
NSTimeInterval _sessionActiveDuration; // Duration that session open. to the console. The default is NO
BOOL _sessionHasBeenOpen; // Whether or not this session has ever been open. */
} @property (nonatomic, assign) BOOL loggingEnabled;
@property dispatch_queue_t queue; /*!
@property dispatch_group_t criticalGroup; @property sessionTimeoutInterval
@property BOOL isSessionOpen; @abstrac (Optional) If an App stays in the background for more than this many seconds,
@property BOOL hasInitialized; start a new session when it returns to foreground.
@property float backgroundSessionTimeout; */
@property (atomic) float sessionTimeoutInterval;
#pragma mark Public Methods
/*! /*!
@method sharedLocalyticsSession @property localyticsDelegate
@abstract Accesses the Session object. This is a Singleton class which maintains @abstract (Optional) Assign this delegate to the class you'd like to register to recieve
a single session throughout your application. It is possible to manage your own the Localytics delegate callbacks (Defined at the end of this file)
session, but this is the easiest way to access the Localytics object throughout your code. */
The class is accessed within the code using the following syntax: @property (nonatomic, assign) id<LocalyticsSessionDelegate> localyticsDelegate;
[[LocalyticsSession sharedLocalyticsSession] functionHere]
So, to tag an event, all that is necessary, anywhere in the code is: #pragma mark Public Methods
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"MY_EVENT"]; /*!
*/ @method shared
+ (LocalyticsSession *)sharedLocalyticsSession; @abstract Accesses the Session object. This is a Singleton class which maintains
a single session throughout your application. It is possible to manage your own
/*! session, but this is the easiest way to access the Localytics object throughout your code.
@method LocalyticsSession The class is accessed within the code using the following syntax:
@abstract Initializes the Localytics Object. Not necessary if you choose to use startSession. [[LocalyticsSession shared] functionHere]
@param applicationKey The key unique for each application generated at www.localytics.com So, to tag an event, all that is necessary, anywhere in the code is:
*/ [[LocalyticsSession shared] tagEvent:@"MY_EVENT"];
- (void)LocalyticsSession:(NSString *)appKey; */
+ (LocalyticsSession *)sharedLocalyticsSession;
/*! + (LocalyticsSession *)shared;
@method startSession
@abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app, /*!
this method fascilitates that behavior. @method startSession
It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>. @abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
@param applicationKey The key unique for each application generated upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app,
at www.localytics.com this method fascilitates that behavior.
*/ It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
- (void)startSession:(NSString *)appKey; @param applicationKey The key unique for each application generated
at www.localytics.com
/*! */
@method setOptIn - (void)startSession:(NSString *)appKey;
@abstract (OPTIONAL) Allows the application to control whether or not it will collect user data.
Even if this call is used, it is necessary to continue calling upload(). No new data will be /*!
collected, so nothing new will be uploaded but it is necessary to upload an event telling the @method open
server this user has opted out. @abstract Opens the Localytics session. Not necessary if you choose to use startSession.
@param optedIn True if the user is opted in, false otherwise. The session time as presented on the website is the time between <code>open</code> and the
*/ final <code>close</code> so it is recommended to open the session as early as possible, and close
- (void)setOptIn:(BOOL)optedIn; it at the last moment. The session must be opened before any tags can
be written. It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
/*! <br>
@method isOptedIn If for any reason this is called more than once every subsequent open call
@abstract (OPTIONAL) Whether or not this user has is opted in or out. The only way they can be will be ignored.
opted out is if setOptIn(false) has been called before this. This function should only be */
used to pre-populate a checkbox in an options menu. It is not recommended that an application - (void)open;
branch based on Localytics instrumentation because this creates an additional test case. If
the app is opted out, all subsequent Localytics calls will return immediately. /*!
@result true if the user is opted in, false otherwise. @method resume
*/ @abstract Resumes the Localytics session. When the App enters the background, the session is
- (BOOL)isOptedIn; closed and the time of closing is recorded. When the app returns to the foreground, the session
is resumed. If the time since closing is greater than BACKGROUND_SESSION_TIMEOUT, (15 seconds
/*! by default) a new session is created, and uploading is triggered. Otherwise, the previous session
@method open is reopened.
@abstract Opens the Localytics session. Not necessary if you choose to use startSession. */
The session time as presented on the website is the time between <code>open</code> and the - (void)resume;
final <code>close</code> so it is recommended to open the session as early as possible, and close
it at the last moment. The session must be opened before any tags can /*!
be written. It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>. @method close
<br> @abstract Closes the Localytics session. This should be called in
If for any reason this is called more than once every subsequent open call <code>applicationWillTerminate</code>.
will be ignored. <br>
*/ If close is not called, the session will still be uploaded but no
- (void)open; events will be processed and the session time will not appear. This is
because the session is not yet closed so it should not be used in
/*! comparison with sessions which are closed.
@method resume */
@abstract Resumes the Localytics session. When the App enters the background, the session is - (void)close;
closed and the time of closing is recorded. When the app returns to the foreground, the session
is resumed. If the time since closing is greater than BACKGROUND_SESSION_TIMEOUT, (15 seconds /*!
by default) a new session is created, and uploading is triggered. Otherwise, the previous session @method tagEvent
is reopened. @abstract Allows a session to tag a particular event as having occurred. For
*/ example, if a view has three buttons, it might make sense to tag
- (void)resume; each button click with the name of the button which was clicked.
For another example, in a game with many levels it might be valuable
/*! to create a new tag every time the user gets to a new level in order
@method close to determine how far the average user is progressing in the game.
@abstract Closes the Localytics session. This should be called in <br>
<code>applicationWillTerminate</code>. <strong>Tagging Best Practices</strong>
<br> <ul>
If close is not called, the session will still be uploaded but no <li>DO NOT use tags to record personally identifiable information.</li>
events will be processed and the session time will not appear. This is <li>The best way to use tags is to create all the tag strings as predefined
because the session is not yet closed so it should not be used in constants and only use those. This is more efficient and removes the risk of
comparison with sessions which are closed. collecting personal information.</li>
*/ <li>Do not set tags inside loops or any other place which gets called
- (void)close; frequently. This can cause a lot of data to be stored and uploaded.</li>
</ul>
/*! <br>
@method tagEvent See the tagging guide at: http://wiki.localytics.com/
@abstract Allows a session to tag a particular event as having occurred. For @param event The name of the event which occurred.
example, if a view has three buttons, it might make sense to tag @param attributes (Optional) An object/hash/dictionary of key-value pairs, contains
each button click with the name of the button which was clicked. contextual data specific to the event.
For another example, in a game with many levels it might be valuable @param rerportAttributes (Optional) Additional attributes used for custom reporting.
to create a new tag every time the user gets to a new level in order Available to Enterprise customers, please contact services for more details.
to determine how far the average user is progressing in the game. @param customerValueIncrease (Optional) Numeric value, added to customer lifetime value.
<br> Integer expected. Try to use lowest possible unit, such as cents for US currency.
<strong>Tagging Best Practices</strong> */
<ul> - (void)tagEvent:(NSString *)event;
<li>DO NOT use tags to record personally identifiable information.</li>
<li>The best way to use tags is to create all the tag strings as predefined - (void)tagEvent:(NSString *)event
constants and only use those. This is more efficient and removes the risk of attributes:(NSDictionary *)attributes;
collecting personal information.</li>
<li>Do not set tags inside loops or any other place which gets called - (void)tagEvent:(NSString *)event
frequently. This can cause a lot of data to be stored and uploaded.</li> attributes:(NSDictionary *)attributes
</ul> customerValueIncrease:(NSNumber *)customerValueIncrease;
<br>
See the tagging guide at: http://wiki.localytics.com/ - (void)tagEvent:(NSString *)event
@param event The name of the event which occurred. attributes:(NSDictionary *)attributes
*/ reportAttributes:(NSDictionary *)reportAttributes;
- (void)tagEvent:(NSString *)event;
- (void)tagEvent:(NSString *)event
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes; attributes:(NSDictionary *)attributes
reportAttributes:(NSDictionary *)reportAttributes
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes; customerValueIncrease:(NSNumber *)customerValueIncrease;
/*!
@method tagScreen /*!
@abstract Allows tagging the flow of screens encountered during the session. @method tagScreen
@param screen The name of the screen @abstract Allows tagging the flow of screens encountered during the session.
*/ @param screen The name of the screen
- (void)tagScreen:(NSString *)screen; */
- (void)tagScreen:(NSString *)screen;
/*!
@method upload /*!
@abstract Creates a low priority thread which uploads any Localytics data already stored @method upload
on the device. This should be done early in the process life in order to @abstract Creates a low priority thread which uploads any Localytics data already stored
guarantee as much time as possible for slow connections to complete. It is also reasonable on the device. This should be done early in the process life in order to
to upload again when the application is exiting because if the upload is cancelled the data guarantee as much time as possible for slow connections to complete. It is also reasonable
will just get uploaded the next time the app comes up. to upload again when the application is exiting because if the upload is cancelled the data
*/ will just get uploaded the next time the app comes up.
- (void)upload; */
- (void)upload;
/*!
@method setCustomDimension /*!
@abstract (ENTERPRISE ONLY) Sets the value of a custom dimension. Custom dimensions are dimensions @method LocalyticsSession
which contain user defined data unlike the predefined dimensions such as carrier, model, and country. @abstract Initializes the Localytics Object. Not necessary if you choose to use startSession.
Once a value for a custom dimension is set, the device it was set on will continue to upload that value @param applicationKey The key unique for each application generated at www.localytics.com
until the value is changed. To clear a value pass nil as the value. */
The proper use of custom dimensions involves defining a dimension with less than ten distinct possible - (void)LocalyticsSession:(NSString *)appKey;
values and assigning it to one of the four available custom dimensions. Once assigned this definition should
never be changed without changing the App Key otherwise old installs of the application will pollute new data. /*!
*/ @method setOptIn
- (void)setCustomDimension:(int)dimension value:(NSString *)value; @abstract (OPTIONAL) Allows the application to control whether or not it will collect user data.
Even if this call is used, it is necessary to continue calling upload(). No new data will be
@end collected, so nothing new will be uploaded but it is necessary to upload an event telling the
server this user has opted out.
@param optedIn True if the user is opted in, false otherwise.
*/
- (void)setOptIn:(BOOL)optedIn;
/*!
@method setLocation
@abstract Stores the user's location. This will be used in all event and session calls.
If your application has already collected the user's location, it may be passed to Localytics
via this function. This will cause all events and the session close to include the locatin
information. It is not required that you call this function.
@param deviceLocation The user's location.
*/
- (void)setLocation:(CLLocationCoordinate2D)deviceLocation;
/*!
@method setCustomDimension
@abstract Sets the value of a custom dimension. Custom dimensions are dimensions
which contain user defined data unlike the predefined dimensions such as carrier, model, and country.
Once a value for a custom dimension is set, the device it was set on will continue to upload that value
until the value is changed. To clear a value pass nil as the value.
The proper use of custom dimensions involves defining a dimension with less than ten distinct possible
values and assigning it to one of the four available custom dimensions. Once assigned this definition should
never be changed without changing the App Key otherwise old installs of the application will pollute new data.
*/
- (void)setCustomDimension:(int)dimension value:(NSString *)value;
/*!
@method customDimension
@abstract Gets the custom dimension value for a given dimension. Avoid calling this on the main thread, as it
may take some time for all pending database execution. */
- (NSString *)customDimension:(int)dimension;
/*!
@method setValueForIdentifier
@abstract Sets the value of a custom identifier. Identifiers are a form of key/value storage
which contain custom user data. Identifiers might include things like email addresses, customer IDs, twitter
handles, and facebook IDs.
Once a value is set, the device it was set on will continue to upload that value until the value is changed.
To delete a property, pass in nil as the value.
*/
- (void)setValueForIdentifier:(NSString *)identifierName value:(NSString *)value;
/*!
@method setCustomerName
@abstract Record the customer name
Once this value is set, the device it was set on will continue to upload that value until the value is changed.
To delete the value, pass in nil.
*/
- (void)setCustomerName:(NSString *)email;
/*!
@method setCustomerId
@abstract Record your custom customer identifier
Once this value is set, the device it was set on will continue to upload that value until the value is changed.
To delete the value, pass in nil.
*/
- (void)setCustomerId:(NSString *)customerId;
/*!
@method setCustomerId
@abstract Record the customer's email address
Once this value is set, the device it was set on will continue to upload that value until the value is changed.
To delete the value, pass in nil.
*/
- (void)setCustomerEmail:(NSString *)email;
@end
@protocol LocalyticsSessionDelegate <NSObject>
@optional
/*!
@method localyticsResumedSession
@abstract Register for this callback to be notified when Localytics has either
resumed a previous session or created a new one. See the on the 'resume' method
for additional details.
@param didResumeExistingSession This flag will indicate if Localytics restored an existing
session or started a new one.
*/
- (void)localyticsResumedSession:(BOOL)didResumeExistingSession;
@end

1455
External/Localytics/LocalyticsSession.m vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
// LocalyticsUploader.h
// Copyright (C) 2013 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
extern NSString * const kLocalyticsKeyResponseBody;
/*!
@class LocalyticsUploader
@discussion Singleton class to handle data uploads
*/
@interface LocalyticsUploader : NSObject {
}
@property (readonly, atomic) BOOL isUploading;
/*!
@method LocalyticsUploader
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
This version of the method now just calls the second version of it with a nil target and NULL callback method.
@param localyticsApplicationKey the Localytics application ID
@param useHTTPS Flag determining whether HTTP or HTTPS is used for the post URL.
@param installId Install id passed to the server in the x-install-id header field.
@param libraryVersion Library version to be passed to the server in the x-client-version header field.
*/
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId libraryVersion:(NSString *)libraryVersion;
/*!
@method LocalyticsUploader
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
@param localyticsApplicationKey the Localytics application ID
@param useHTTPS Flag determining whether HTTP or HTTPS is used for the post URL.
@param installId Install id passed to the server in the x-install-id header field.
@param libraryVersion Library version to be passed to the server in the x-client-version header field.
@param resultTarget Result target is the target for the callback method that knows how to handle response data
@param callback Callback is the method of the target class that is to be called with the data begin returned by an upload
*/
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId libraryVersion:(NSString *)libraryVersion resultTarget:(id)target callback:(SEL)callbackMethod;
/*!
@method LocalyticsUploader
@abstract Upload attribution data to Localytics.
@param localyticsApplicationKey the Localytics application ID
@param attribution Attribution cookie captured at install time
@param installId Install id passed to the server in the x-install-id header field.
@param advertisingIdentifier The Apple 'advertisingidentifier'
*/
- (void)uploaderAttributionWithApplicationKey:(NSString *)appKey attribution:(NSString *)attribution installId:(NSString *)installId advertisingIdentifier:(NSString *)advertisingIdentifier;
/*!
@method uploadTimeStamp
@abstract Retrieve upload TimeStamp.
*/
- (NSString *)uploadTimeStamp;
@end

343
External/Localytics/LocalyticsUploader.m vendored Normal file
View File

@@ -0,0 +1,343 @@
// LocalyticsUploader.m
// Copyright (C) 2013 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import "LocalyticsUploader.h"
#import "LocalyticsSession.h"
#import "LocalyticsSession+Private.h"
#import "LocalyticsDatabase.h"
#import "WebserviceConstants.h"
#import <zlib.h>
#ifndef LOCALYTICS_URL
#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads"
#endif
#ifndef LOCALYTICS_URL_SECURED
#define LOCALYTICS_URL_SECURED @"https://analytics.localytics.com/api/v2/applications/%@/uploads"
#endif
#ifndef LOCALYTICS_ATTRIBUTION_SERVER
#define LOCALYTICS_ATTRIBUTION_SERVER @"http://a.localytics.com/fb_install/"
#endif
NSString * const kLocalyticsKeyResponseBody = @"localytics.key.responseBody";
@interface LocalyticsUploader ()
- (void)finishUpload;
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
@property (readwrite) BOOL isUploading;
@end
@implementation LocalyticsUploader
@synthesize isUploading = _isUploading;
#pragma mark - Class Methods
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId libraryVersion:(NSString *)libraryVersion
{
[self uploaderWithApplicationKey:localyticsApplicationKey useHTTPS:useHTTPS installId:installId libraryVersion:libraryVersion resultTarget:nil callback:NULL];
}
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId libraryVersion:(NSString *)libraryVersion resultTarget:(id)target callback:(SEL)callbackMethod
{
// Do nothing if already uploading.
if (self.isUploading == true)
{
LocalyticsLog("Upload already in progress. Aborting.");
return;
}
LocalyticsLog("Beginning upload process");
self.isUploading = true;
// Prepare the data for upload. The upload could take a long time, so some effort has to be made to be sure that events
// which get written while the upload is taking place don't get lost or duplicated. To achieve this, the logic is:
// 1) Append every header row blob string and and those of its associated events to the upload string.
// 2) Deflate and upload the data.
// 3) On success, delete all blob headers and staged events. Events added while an upload is in process are not
// deleted because they are not associated a header (and cannot be until the upload completes).
// Step 1
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
LocalyticsDatabase *db = [[LocalyticsSession shared] db];
NSString *blobString = [db uploadBlobString];
if ([blobString length] == 0) {
// There is nothing outstanding to upload.
LocalyticsLog("Abandoning upload. There are no new events.");
[pool drain];
[self finishUpload];
return;
}
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
if(LOCALYTICS_LOGGING_ENABLED) {
NSString *logString = [[[NSString alloc] initWithData:requestData
encoding:NSUTF8StringEncoding] autorelease];
NSUInteger stringLength = [logString length];
logString = [logString stringByReplacingOccurrencesOfString:@"{"
withString:@"\n\t{"];
logString = [logString stringByReplacingOccurrencesOfString:@",\""
withString:@",\n\t\""];
LocalyticsLog("Uploading data (length: %u)\n%@",
stringLength,
logString);
}
// Step 2
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
[pool drain];
NSString *urlStringFormat;
if (useHTTPS) {
urlStringFormat = LOCALYTICS_URL_SECURED;
} else {
urlStringFormat = LOCALYTICS_URL;
}
NSURL *apiUrl = [NSURL URLWithString:[NSString stringWithFormat:urlStringFormat,[localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
NSMutableURLRequest *submitRequest = [self createRequestWithURL:apiUrl
installId:installId
libraryVersion:libraryVersion
requestData:deflatedRequestData];
[deflatedRequestData release];
// Perform synchronous upload in an async dispatch. This is necessary because the calling block will not persist to
// receive the response data.
dispatch_group_async([[LocalyticsSession shared] criticalGroup], [[LocalyticsSession shared] queue], ^{
@try {
NSURLResponse *response = nil;
NSError *responseError = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:submitRequest returningResponse:&response error:&responseError];
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
if (responseError) {
// On error, simply print the error and close the uploader. We have to assume the data was not transmited
// so it is not deleted. In the event that we accidently store data which was succesfully uploaded, the
// duplicate data will be ignored by the server when it is next uploaded.
LocalyticsLog("Error Uploading. Code: %d, Description: %@",
[responseError code],
[responseError localizedDescription]);
} else {
// Step 3
// While response status codes in the 5xx range leave upload rows intact, the default case is to delete.
if (responseStatusCode >= 500 && responseStatusCode < 600) {
LocalyticsLog("Upload failed with response status code %d", responseStatusCode);
} else {
// Because only one instance of the uploader can be running at a time it should not be possible for
// new upload rows to appear so there is no fear of deleting data which has not yet been uploaded.
LocalyticsLog("Upload completed successfully. Response code %d", responseStatusCode);
[[[LocalyticsSession shared] db] deleteUploadedData];
}
}
if ([responseData length] > 0) {
if (LOCALYTICS_LOGGING_ENABLED) {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
LocalyticsLog("Response body: %@", responseString);
[responseString release];
}
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:responseData forKey:kLocalyticsKeyResponseBody];
if (target) {
[target performSelector:callbackMethod withObject:userInfo];
}
}
[self finishUpload];
}
@catch (NSException * e) {}
});
}
- (NSMutableURLRequest *)createRequestWithURL:(NSURL *)URL installId:(NSString *)installId libraryVersion:(NSString *)libraryVersion requestData:(NSData *)requestData
{
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:URL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
[submitRequest setHTTPMethod:@"POST"];
[submitRequest setValue:[self uploadTimeStamp] forHTTPHeaderField:HEADER_CLIENT_TIME];
[submitRequest setValue:installId forHTTPHeaderField:HEADER_INSTALL_ID];
[submitRequest setValue:libraryVersion forHTTPHeaderField:HEADER_CLIENT_VERSION];
[submitRequest setValue:@"application/x-gzip" forHTTPHeaderField:@"Content-Type"];
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
[submitRequest setValue:[NSString stringWithFormat:@"%d", requestData.length] forHTTPHeaderField:@"Content-Length"];
if ([LocalyticsSession shared].delaySession == YES)
{
[submitRequest setValue:@"true" forHTTPHeaderField:HEADER_DELAY_SESSION];
}
[submitRequest setHTTPBody:requestData];
return submitRequest;
}
- (void)finishUpload
{
self.isUploading = false;
// Upload data has been deleted. Recover the disk space if necessary.
[[[LocalyticsSession shared] db] vacuumIfRequired];
}
- (void)uploaderAttributionWithApplicationKey:(NSString *)appKey attribution:(NSString *)attribution installId:(NSString *)installId advertisingIdentifier:(NSString *)advertisingIdentifier
{
// Required parameters
if(!attribution)
return;
NSString *apiUrlString = [LOCALYTICS_ATTRIBUTION_SERVER stringByAppendingString:appKey];
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
NSMutableString *postBody = [NSMutableString string];
[postBody appendFormat:@"%@=%@", FB_ATTRIBUTION, attribution];
[postBody appendFormat:@"&%@=%ld", FB_ATTRIBUTION_TIME, (long)[[[LocalyticsSession shared] db] createdTimestamp]];
if(advertisingIdentifier)
{
[postBody appendFormat:@"&%@=%@", FB_DEVICE_ID_TYPE, @"adid"];
[postBody appendFormat:@"&%@=%@", FB_DEVICE_ID, advertisingIdentifier];
}
if(installId)
{
[postBody appendFormat:@"&%@=%@", FB_INSTALL_ID, installId];
}
[submitRequest setHTTPMethod:@"POST"];
[submitRequest setHTTPBody:[postBody dataUsingEncoding:NSUTF8StringEncoding]];
// Perform synchronous upload in an async dispatch. This is necessary because the calling block will not persist to
// receive the response data.
dispatch_group_async([[LocalyticsSession shared] criticalGroup], [[LocalyticsSession shared] queue], ^{
@try {
NSURLResponse *response = nil;
NSError *responseError = nil;
[NSURLConnection sendSynchronousRequest:submitRequest
returningResponse:&response
error:&responseError];
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
if (responseError) {
// On error, simply print the error and close the uploader. We have to assume the data was not transmited
// so it is not deleted.
LocalyticsLog("Error uploading Facebook attribution. Code: %d, Description: %@",
[responseError code],
[responseError localizedDescription]);
}
else
{
// While response status codes in the 5xx range leave upload rows intact, the default case is to delete.
if (responseStatusCode >= 500 && responseStatusCode < 600) {
LocalyticsLog("Facebook attribution upload unsuccessful. Response code %d", responseStatusCode);
}
else
{
LocalyticsLog("Facebook attribution upload completed successfully. Response code %d", responseStatusCode);
[[[LocalyticsSession shared] db] setFacebookAttribution:nil];
[LocalyticsSession shared].facebookAttribution = nil;
}
}
}
@catch (NSException * e) {}
});
}
/*!
@method gzipDeflatedDataWithData
@abstract Deflates the provided data using gzip at the default compression level (6).
@return the deflated data
*/
- (NSData *)gzipDeflatedDataWithData:(NSData *)data
{
if ([data length] == 0) return data;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
/*!
@method uploadTimeStamp
@abstract Gets the current time, along with local timezone, formatted as a DateTime for the webservice.
@return a DateTime of the current local time and timezone.
*/
- (NSString *)uploadTimeStamp {
return [ NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970] ];
}
#pragma mark - System Functions
- (id)copyWithZone:(NSZone *)zone {
#pragma unused(zone)
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
// maximum value of an unsigned int - prevents additional retains for the class
return UINT_MAX;
}
- (oneway void)release {
// ignore release commands
}
- (id)autorelease {
return self;
}
@end

View File

@@ -1,15 +1,23 @@
// WebserviceConstants.h // WebserviceConstants.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics // Copyright (C) 2013 Char Software Inc., DBA Localytics
// //
// This code is provided under the Localytics Modified BSD License. // This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE // A copy of this license has been distributed in a file called LICENSE
// with this source code. // with this source code.
// //
// Please visit www.localytics.com for more information. // Please visit www.localytics.com for more information.
// The constants which are used to make up the JSON blob // The constants which are used to make up the JSON blob
// To save disk space and network bandwidth all the keywords have been // To save disk space and network bandwidth all the keywords have been
// abbreviated and are exploded by the server. // abbreviated and are exploded by the server.
/*****************
* Upload Header *
*****************/
#define HEADER_CLIENT_TIME @"x-upload-time"
#define HEADER_INSTALL_ID @"x-install-id"
#define HEADER_CLIENT_VERSION @"x-client-version"
#define HEADER_DELAY_SESSION @"ll-first-session"
/********************* /*********************
* Shared Attributes * * Shared Attributes *
@@ -22,6 +30,7 @@
#define PARAM_SESSION_UUID @"su" // UUID for an existing session #define PARAM_SESSION_UUID @"su" // UUID for an existing session
#define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session #define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session
#define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary) #define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary)
#define PARAM_SESSION_ELAPSE_TIME @"sl" // Number of seconds since the previous session start
/*************** /***************
* Blob Header * * Blob Header *
@@ -31,7 +40,7 @@
// PARAM_DATA_TYPE => "h" for Header // PARAM_DATA_TYPE => "h" for Header
// PARAM_ATTRIBUTES => dictionary containing Header Common Attributes // PARAM_ATTRIBUTES => dictionary containing Header Common Attributes
#define PARAM_PERSISTED_AT @"pa" // Persistent Storage Created At. A timestamp created when the app was #define PARAM_PERSISTED_AT @"pa" // Persistent Storage Created At. A timestamp created when the app was
// first launched and the persistent storage was created. Stores as // first launched and the persistent storage was created. Stores as
// seconds from Unix epoch. (int) // seconds from Unix epoch. (int)
#define PARAM_SEQUENCE_NUMBER @"seq" // Sequence number - an increasing count for each blob, stored in the #define PARAM_SEQUENCE_NUMBER @"seq" // Sequence number - an increasing count for each blob, stored in the
// persistent store Consistent across app starts. (int) // persistent store Consistent across app starts. (int)
@@ -42,9 +51,8 @@
// PARAM_DATA_TYPE // PARAM_DATA_TYPE
#define PARAM_APP_KEY @"au" // Localytics Application ID #define PARAM_APP_KEY @"au" // Localytics Application ID
#define PARAM_DEVICE_UUID @"du" // Device UUID
#define PARAM_DEVICE_UUID_HASHED @"udid" // Hashed version of the UUID #define PARAM_DEVICE_UUID_HASHED @"udid" // Hashed version of the UUID
#define PARAM_DEVICE_MAC @"wmac" // Hashed version of the device Mac #define PARAM_DEVICE_ADID @"adid" // Advertising Identifier
#define PARAM_INSTALL_ID @"iu" // Install ID #define PARAM_INSTALL_ID @"iu" // Install ID
#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean) #define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
#define PARAM_LIBRARY_VERSION @"lv" // Client Version #define PARAM_LIBRARY_VERSION @"lv" // Client Version
@@ -52,15 +60,15 @@
#define PARAM_DEVICE_PLATFORM @"dp" // Device Platform #define PARAM_DEVICE_PLATFORM @"dp" // Device Platform
#define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language #define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language
#define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country #define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country
#define PARAM_NETWORK_COUNTRY @"nc" // Network Country (iso code) // ???: Never used on iPhone.
#define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code) #define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code)
#define PARAM_DEVICE_MANUFACTURER @"dma" // Device Manufacturer // ???: Never used on iPhone. Used to be "Device Make".
#define PARAM_DEVICE_MODEL @"dmo" // Device Model #define PARAM_DEVICE_MODEL @"dmo" // Device Model
#define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version #define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version
#define PARAM_NETWORK_CARRIER @"nca" // Network Carrier #define PARAM_NETWORK_CARRIER @"nca" // Network Carrier
#define PARAM_DATA_CONNECTION @"dac" // Data Connection Type // ???: Never used on iPhone. #define PARAM_OPT_VALUE @"out" // Opt Out (boolean)
#define PARAM_OPT_VALUE @"optin" // Opt In (boolean)
#define PARAM_DEVICE_MEMORY @"dmem" // Device Memory #define PARAM_DEVICE_MEMORY @"dmem" // Device Memory
#define PARAM_IDENTIFIERS @"ids" // Identifiers (dictionary)
#define PARAM_BIRTH_TIME @"b" // Birth time (Since epoch)
#define PARAM_TIMEZONE_OFFSET @"tz" // Device offset from GMT in seconds
/***************** /*****************
* Session Start * * Session Start *
@@ -98,6 +106,7 @@
// PARAM_ATTRIBUTES => dictionary containing attributes for this event as key-value string pairs // PARAM_ATTRIBUTES => dictionary containing attributes for this event as key-value string pairs
#define PARAM_EVENT_NAME @"n" // Event Name, (eg. 'Button Click') #define PARAM_EVENT_NAME @"n" // Event Name, (eg. 'Button Click')
#define PARAM_REPORT_ATTRIBUTES @"rattrs" // Attributes used in custom reports #define PARAM_REPORT_ATTRIBUTES @"rattrs" // Attributes used in custom reports
#define PARAM_VALUE_NAME @"v" // Added customer value for an event, such as revenue
/******************** /********************
* Application flow * * Application flow *
@@ -108,4 +117,17 @@
// PARAM_CLIENT_TIME // PARAM_CLIENT_TIME
#define PARAM_SESSION_START @"ss" // Start time for the current session. #define PARAM_SESSION_START @"ss" // Start time for the current session.
#define PARAM_NEW_FLOW_EVENTS @"nw" // Events and screens encountered during this session that have NOT been staged for upload. #define PARAM_NEW_FLOW_EVENTS @"nw" // Events and screens encountered during this session that have NOT been staged for upload.
#define PARAM_OLD_FLOW_EVENTS @"od" // Events and screens encountered during this session that HAVE been staged for upload. #define PARAM_OLD_FLOW_EVENTS @"od" // Events and screens encountered during this session that HAVE been staged for upload.
/************************
* Partner attributions *
***********************/
#define FB_ATTRIBUTION @"fb_attrib_first" // Facebook attribution cookie
#define FB_ATTRIBUTION_TIME @"fb_attrib_first_date" // Time original attribution cookie was collected
#define FB_ATTRIBUTION_CURRENT @"fb_attrib_current" // Facebook attribution cookie
#define FB_ATTRIBUTION_CURRENT_TIME @"fb_attrib_current_date" // Time original attribution cookie was collected
#define FB_DEVICE_ID @"dpid" // Device unique identifiers
#define FB_DEVICE_ID_TYPE @"dpid_type" // Either UDID or ADID (advertisingIdentifier)
#define FB_INSTALL_ID @"install_id" // Device install ID

2
External/Pearl vendored

View File

@@ -1,24 +1,4 @@
Thanks for downloading the TestFlight SDK 1.0! ##Introduction
This document is also available on the web at https://www.testflightapp.com/sdk/doc
1. Why use the TestFlight SDK?
2. Considerations
3. How do I integrate the SDK into my project?
4. Beta Testing and Release Differentiation
5. Using the Checkpoint API
6. Using the Feedback API
7. Upload your build
8. Questions API
9. View your results
10. Advanced Exception Handling
11. Remote Logging
12. iOS 3
START
1. Why use the TestFlight SDK?
The TestFlight SDK allows you to track how beta testers are testing your application. Out of the box we track simple usage information, such as which tester is using your application, their device model/OS, how long they used the application, logs of their test session, and automatic recording of any crashes they encounter. The TestFlight SDK allows you to track how beta testers are testing your application. Out of the box we track simple usage information, such as which tester is using your application, their device model/OS, how long they used the application, logs of their test session, and automatic recording of any crashes they encounter.
@@ -30,34 +10,29 @@ Alongside the Checkpoint API is the Questions interface. The Questions interface
For more detailed debugging we have a remote logging solution. Find out more about our logging system with TFLog in the Remote Logging section. For more detailed debugging we have a remote logging solution. Find out more about our logging system with TFLog in the Remote Logging section.
2. Considerations
##Considerations
Information gathered by the SDK is sent to the website in real time. When an application is put into the background (iOS 4.x) or terminated (iOS 3.x) we try to send the finalizing information for the session during the time allowed for finalizing the application. Should all of the data not get sent the remaining data will be sent the next time the application is launched. As such, to get the most out of the SDK we recommend your application support iOS 4.0 and higher. Information gathered by the SDK is sent to the website in real time. When an application is put into the background (iOS 4.x) or terminated (iOS 3.x) we try to send the finalizing information for the session during the time allowed for finalizing the application. Should all of the data not get sent the remaining data will be sent the next time the application is launched. As such, to get the most out of the SDK we recommend your application support iOS 4.0 and higher.
This SDK can be run from both the iPhone Simulator and Device and has been tested using Xcode 4.0. This SDK can be run from both the iPhone Simulator and Device and has been tested using Xcode 4.0.
3. How do I integrate the SDK into my project?
##Integration
1. Add the files to your project: File -> Add Files to "<your project name>"
1. Add the files to your project: File -&gt; Add Files to " "
1. Find and select the folder that contains the SDK 1. Find and select the folder that contains the SDK
2. Make sure that "Copy items into destination folder (if needed)" is checked 2. Make sure that "Copy items into destination folder (if needed)" is checked
3. Set Folders to "Create groups for any added folders" 3. Set Folders to "Create groups for any added folders"
4. Select all targets that you want to add the SDK to 4. Select all targets that you want to add the SDK to
2. Verify that libTestFlight.a has been added to the Link Binary With Libraries Build Phase for the targets you want to use the SDK with
2. Verify that libTestFlight.a and has been added to the Link Binary With Libraries Build Phase for the targets you want to use the SDK with
1. Select your Project in the Project Navigator 1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for 2. Select the target you want to enable the SDK for
3. Select the Build Phases tab 3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase 4. Open the Link Binary With Libraries Phase
5. If libTestFlight.a is not listed, drag and drop the library from your Project Navigator to the Link Binary With Libraries area 5. If libTestFlight.a is not listed, drag and drop the library from your Project Navigator to the Link Binary With Libraries area
6. Repeat Steps 2 - 5 until all targets you want to use the SDK with have the SDK linked 6. Repeat Steps 2 - 5 until all targets you want to use the SDK with have the SDK linked
3. Add libz to your Link Binary With Libraries Build Phase 3. Add libz to your Link Binary With Libraries Build Phase
1. Select your Project in the Project Navigator 1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for 2. Select the target you want to enable the SDK for
3. Select the Build Phases tab 3. Select the Build Phases tab
@@ -65,138 +40,135 @@ This SDK can be run from both the iPhone Simulator and Device and has been teste
5. Click the + to add a new library 5. Click the + to add a new library
6. Find libz.dylib in the list and add it 6. Find libz.dylib in the list and add it
7. Repeat Steps 2 - 6 until all targets you want to use the SDK with have libz.dylib 7. Repeat Steps 2 - 6 until all targets you want to use the SDK with have libz.dylib
4. In your Application Delegate: 4. In your Application Delegate:
1. Import TestFlight: `#import "TestFlight.h"`
***NOTE:*** Rather than importing `TestFlight.h` in every file you may add the above line into you pre-compiled header (`<projectname>_Prefix.pch`) file inside of the
1. Import TestFlight: `#import "TestFlight.h"`
NOTE: If you do not want to import TestFlight.h in every file you may add the above line into you pre-compiled header (`<projectname>_Prefix.pch`) file inside of the
#ifdef __OBJC__ #ifdef __OBJC__
section.
This will give you access to the SDK across all files.
2. Get your Team Token which you can find at [http://testflightapp.com/dashboard/team/](http://testflightapp.com/dashboard/team/) select the team you are using from the team selection drop down list on the top of the page and then select Team Info.
3. Launch TestFlight with your Team Token section. This will give you access to the SDK across all files.
2. Get your Application Token which you can find at [http://testflightapp.com/dashboard/applications/](http://testflightapp.com/dashboard/applications/) select the application you are using from the list choose the SDK option and the application token for this application will be there. To ensure that your testers do not show up as anonymous place the call to setDeviceIdentifer before calling takeOff. Remove #define TESTING 1 before building your release build for the App Store.
3. Launch TestFlight with your Application Token
-(BOOL)application:(UIApplication *)application -(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// start of your application:didFinishLaunchingWithOptions // start of your application:didFinishLaunchingWithOptions
// ...
[TestFlight takeOff:@"Insert your Team Token here"]; // !!!: Use the next line only during beta
// The rest of your application:didFinishLaunchingWithOptions method // [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
// ...
[TestFlight takeOff:@"Insert your Application Token here"];
// The rest of your application:didFinishLaunchingWithOptions method
// ...
} }
4. To report crashes to you we install our own uncaught exception handler. If you are not currently using an exception handler of your own then all you need to do is go to the next step. If you currently use an Exception Handler, or you use another framework that does please go to the section on advanced exception handling. 4. To report crashes to you we install our own uncaught exception handler. If you are not currently using an exception handler of your own then all you need to do is go to the next step. If you currently use an Exception Handler, or you use another framework that does please go to the section on advanced exception handling.
5. To enable the best crash reporting possible we recommend setting the following project build settings in Xcode to NO for all targets that you want to have live crash reporting for. You can find build settings by opening the Project Navigator (default command+1 or command+shift+j) then clicking on the project you are configuring (usually the first selection in the list). From there you can choose to either change the global project settings or settings on an individual project basis. All settings below are in the Deployment Section.
1. Deployment Postrocessing ##Beta Testing and Release Differentiation
2. Strip Debug Symbols During Copy
3. Strip Linked Product
In order to provide more information about your testers while beta testing you will need to provide the device's unique identifier. This identifier is not something that the SDK will collect from the device and we do not recommend using this in production. To send the device identifier to us put the following code **before your call to takeOff**.
4. Beta Testing and Release Differentiation [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
[TestFlight takeOff:@"Insert your Application Token here"];
In order to provide more information about your testers while beta testing you will need to provide the device's unique identifier. This identifier is not something that the SDK will collect from the device and we do not recommend using this in production. Here is the recommended code for providing the device unique identifier. This will allow you to have the best possible information during testing. **When it is time to submit to the App Store comment this line out**. Apple may reject your app if you leave this line in. If you decide to not include the device's unique identifier during your testing phase TestFlight will still collect all of the information that you send but it may be anonymized.
#define TESTING 1
#ifdef TESTING ##Checkpoint API
[TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
#endif
This will allow you to have the best possible information during testing, but disable getting and sending of the device unique identifier when you release your application. When it is time to release simply comment out #define TESTING 1. If you decide to not include the device's unique identifier during your testing phase TestFlight will still collect all of the information that you send but it may be anonymized. When a tester does something you care about in your app you can pass a checkpoint. For example completing a level, adding a todo item, etc. The checkpoint progress is used to provide insight into how your testers are testing your apps. The passed checkpoints are also attached to crashes, which can help when creating steps to replicate.
5. Use the Checkpoint API to create important checkpoints throughout your application. `[TestFlight passCheckpoint:@"CHECKPOINT_NAME"];` Use `passCheckpoint:` to track when a user performs certain tasks in your application. This can be useful for making sure testers are hitting all parts of your application, as well as tracking which testers are being thorough.
When a tester does something you care about in your app you can pass a checkpoint. For example completing a level, adding a todo item, etc. The checkpoint progress is used to provide insight into how your testers are testing your apps. The passed checkpoints are also attached to crashes, which can help when creating steps to replicate. ##Feedback API
`[TestFlight passCheckpoint:@"CHECKPOINT_NAME"];` To launch unguided feedback call the openFeedbackView method. We recommend that you call this from a GUI element.
Use `+passCheckpoint:` to track when a user performs certain tasks in your application. This can be useful for making sure testers are hitting all parts of your application, as well as tracking which testers are being thorough.
6. Using the Feedback API
To launch unguided feedback call the `openFeedbackView` method. We recommend that you call this from a GUI element.
-(IBAction)launchFeedback { -(IBAction)launchFeedback {
[TestFlight openFeedbackView]; [TestFlight openFeedbackView];
} }
If you want to create your own feedback form you can use the `submitCustomFeedback` method to submit the feedback that the user has entered. If you want to create your own feedback form you can use the submitCustomFeedback method to submit the feedback that the user has entered.
-(IBAction)submitFeedbackPressed:(id)sender { -(IBAction)submitFeedbackPressed:(id)sender {
NSString *feedback = [self getUserFeedback]; NSString *feedback = [self getUserFeedback];
[TestFlight submitCustomFeedback:feedback]; [TestFlight submitFeedback:feedback];
} }
The above sample assumes that [self getUserFeedback] is implemented such that it obtains the users feedback from the GUI element you have created and that submitFeedbackPressed is the action for your submit button. The above sample assumes that [self getUserFeedback] is implemented such that it obtains the users feedback from the GUI element you have created and that submitFeedbackPressed is the action for your submit button.
Once users have submitted feedback from inside of the application you can view it in the feedback area of your build page. Once users have submitted feedback from inside of the application you can view it in the feedback area of your build page.
7. Upload your build.
After you have integrated the SDK into your application you need to upload your build to TestFlight. You can upload from your dashboard or or using the Upload API, full documentation at <https://testflightapp.com/api/doc/> ##Upload your build
After you have integrated the SDK into your application you need to upload your build to TestFlight. You can upload from your dashboard or or using the Upload API, full documentation at [https://testflightapp.com/api/doc/](https://testflightapp.com/api/doc/)
8. Add Questions to Checkpoints ##Questions Interface
In order to ask a question, you'll need to associate it with a checkpoint. Make sure your checkpoints are initialized by running your app and hitting them all yourself before you start adding questions. In order to ask a question, you'll need to associate it with a checkpoint. Make sure your checkpoints are initialized by running your app and hitting them all yourself before you start adding questions.
There are three question types available: Yes/No, Multiple Choice, and Long Answer. There are three question types available: Yes/No, Multiple Choice, and Long Answer.
To create questions, visit your builds Questions page and click on 'Add Question'. If you choose Multiple Choice, you'll need to enter a list of possible answers for your testers to choose from &mdash; otherwise, you'll only need to enter your question's, well, question. If your build has no questions, you can also choose to migrate questions from another build (because seriously &mdash; who wants to do all that typing again)? To create questions, visit your builds Questions page and click on 'Add Question'. If you choose Multiple Choice, you'll need to enter a list of possible answers for your testers to choose from otherwise, you'll only need to enter your question's, well, question. If your build has no questions, you can also choose to migrate questions from another build (because seriously who wants to do all that typing again)?
After restarting your application on an approved device, when you pass the checkpoint associated with your questions a TestFlight modal question form will appear on the screen asking the beta tester to answer your question. After restarting your application on an approved device, when you pass the checkpoint associated with your questions a TestFlight modal question form will appear on the screen asking the beta tester to answer your question.
After you upload a new build to TestFlight you will need to associate questions once again. However if your checkpoints and questions have remained the same you can choose "copy questions from an older build" and choose which build to copy the questions from. After you upload a new build to TestFlight you will need to associate questions once again. However if your checkpoints and questions have remained the same you can choose "copy questions from an older build" and choose which build to copy the questions from.
9. View your results. ##View the results
As testers install your build and start to test it you will see their session data on the web on the build report page for the build you've uploaded. As testers install your build and start to test it you will see their session data on the web on the build report page for the build you've uploaded.
10. Advanced Exception Handling ##Advanced Exception Handling
An uncaught exception means that your application is in an unknown state and there is not much that you can do but try and exit gracefully. Our SDK does its best to get the data we collect in this situation to you while it is crashing, but it is designed in such a way that the important act of saving the data occurs in as safe way a way as possible before trying to send anything. If you do use uncaught exception or signal handlers install your handlers before calling `takeOff`. Our SDK will then call your handler while ours is running. For example: An uncaught exception means that your application is in an unknown state and there is not much that you can do but try and exit gracefully. Our SDK does its best to get the data we collect in this situation to you while it is crashing, but it is designed in such a way that the important act of saving the data occurs in as safe way a way as possible before trying to send anything. If you do use uncaught exception or signal handlers install your handlers before calling `takeOff`. Our SDK will then call your handler while ours is running. For example:
/* /*
My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest
**/ */
void HandleExceptions(NSException *exception) { void HandleExceptions(NSException *exception) {
NSLog(@"This is where we save the application data during a exception"); NSLog(@"This is where we save the application data during a exception");
// Save application data on crash // Save application data on crash
} }
/* /*
My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest
**/ */
void SignalHandler(int sig) { void SignalHandler(int sig) {
NSLog(@"This is where we save the application data during a signal"); NSLog(@"This is where we save the application data during a signal");
// Save application data on crash // Save application data on crash
} }
-(BOOL)application:(UIApplication *)application -(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// installs HandleExceptions as the Uncaught Exception Handler // installs HandleExceptions as the Uncaught Exception Handler
NSSetUncaughtExceptionHandler(&HandleExceptions); NSSetUncaughtExceptionHandler(&HandleExceptions);
// create the signal action structure // create the signal action structure
struct sigaction newSignalAction; struct sigaction newSignalAction;
// initialize the signal action structure // initialize the signal action structure
memset(&newSignalAction, 0, sizeof(newSignalAction)); memset(&newSignalAction, 0, sizeof(newSignalAction));
// set SignalHandler as the handler in the signal action structure // set SignalHandler as the handler in the signal action structure
newSignalAction.sa_handler = &SignalHandler; newSignalAction.sa_handler = &SignalHandler;
// set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS // set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS
sigaction(SIGABRT, &newSignalAction, NULL); sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL); sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL); sigaction(SIGBUS, &newSignalAction, NULL);
// Call takeOff after install your own unhandled exception and signal handlers // Call takeOff after install your own unhandled exception and signal handlers
[TestFlight takeOff:@"Insert your Team Token here"]; [TestFlight takeOff:@"Insert your Application Token here"];
// continue with your application initialization // continue with your application initialization
} }
You do not need to add the above code if your application does not use exception handling already. You do not need to add the above code if your application does not use exception handling already.
11. Remote Logging ##Remote Logging
To perform remote logging you can use the TFLog method which logs in a few different methods described below. In order to make the transition from NSLog to TFLog easy we have used the same method signature for TFLog as NSLog. You can easily switch over to TFLog by adding the following macro to your header To perform remote logging you can use the TFLog method which logs in a few different methods described below. In order to make the transition from NSLog to TFLog easy we have used the same method signature for TFLog as NSLog. You can easily switch over to TFLog by adding the following macro to your header
#define NSLog TFLog #define NSLog TFLog
@@ -217,32 +189,33 @@ We have implemented three different loggers.
Each of the loggers log asynchronously and all TFLog calls are non blocking. The TestFlight logger writes its data to a file which is then sent to our servers on Session End events. The Apple System Logger sends its messages to the Apple System Log and are viewable using the Organizer in Xcode when the device is attached to your computer. The ASL logger can be disabled by turning it off in your TestFlight options Each of the loggers log asynchronously and all TFLog calls are non blocking. The TestFlight logger writes its data to a file which is then sent to our servers on Session End events. The Apple System Logger sends its messages to the Apple System Log and are viewable using the Organizer in Xcode when the device is attached to your computer. The ASL logger can be disabled by turning it off in your TestFlight options
[TestFlight setOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"logToConsole"]]; [TestFlight setOptions:{ TFOptionLogToConsole : @NO }];
The default option is YES. The default option is YES.
The STDERR logger sends log messages to STDERR so that you can see your log statements while debugging. The STDERR logger is only active when a debugger is attached to your application. If you do not wish to use the STDERR logger you can disable it by turning it off in your TestFlight options The STDERR logger sends log messages to STDERR so that you can see your log statements while debugging. The STDERR logger is only active when a debugger is attached to your application. If you do not wish to use the STDERR logger you can disable it by turning it off in your TestFlight options
[TestFlight setOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"logToSTDERR"]]; [TestFlight setOptions:{ TFOptionLogToSTDERR : @NO }];
The default option is YES. The default option is YES.
12. iOS3 ## Advanced Remote Logging
We now require that anyone who is writing an application that supports iOS3 add the System.framework as an optional link. In order to provide a better shutdown experience we send any large log files to our servers in the background. To add System.framework as an optional link: For most users we expect using TFLog to provide all of the logging functionality that they need. For the occasion where you need to provide a wrapper around TFLog we provide
1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for
3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase
5. Click the + to add a new library
6. Find libSystem.dylib in the list and add it
7. To the right of libSystem.dylib in the Link Binary With Libraries pane change "Required" to "Optional"
END void TFLogv(NSString *format, va_list arg_list);
Please contact us if you have any questions. Using TFLogv you can have your method that accepts a variable number of arguments that then passes that format and argument list to TFLog.
The TestFlight Team
w. http://www.testflightapp.com ##iOS3
e. beta@testflightapp.com
We now require that anyone who is writing an application that supports iOS3 add the System.framework as an optional link. In order to provide a better shutdown experience we send any large log files to our servers in the background. To add System.framework as an optional link:
1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for
3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase
5. Click the + to add a new library
6. Find libSystem.dylib in the list and add it
7. To the right of libSystem.dylib in the Link Binary With Libraries pane change "Required" to "Optional"

114
External/TestFlight/TestFlight.h vendored Normal file
View File

@@ -0,0 +1,114 @@
//
// TestFlight.h
// libTestFlight
//
// Created by Jonathan Janzen on 06/11/11.
// Copyright 2011 TestFlight. All rights reserved.
#import <Foundation/Foundation.h>
#define TESTFLIGHT_SDK_VERSION @"1.2.4"
#undef TFLog
#if __cplusplus
extern "C" {
#endif
void TFLog(NSString *format, ...);
void TFLogv(NSString *format, va_list arg_list);
#if __cplusplus
}
#endif
/**
* TestFlight object
* All methods are class level
*/
@interface TestFlight : NSObject {
}
/**
* Add custom environment information
* If you want to track custom information such as a user name from your application you can add it here
*
* @param information A string containing the environment you are storing
* @param key The key to store the information with
*/
+ (void)addCustomEnvironmentInformation:(NSString *)information forKey:(NSString*)key;
/**
* Starts a TestFlight session using the Application Token for this Application
*
* @param applicationToken Will be the application token for the current application.
* The token for this application can be retrieved by going to https://testflightapp.com/dashboard/applications/
* selecting this application from the list then selecting SDK.
*/
+ (void)takeOff:(NSString *)applicationToken;
/**
* Sets custom options
*
* @param options NSDictionary containing the options you want to set. Available options are described below at "TestFlight Option Keys"
*
*/
+ (void)setOptions:(NSDictionary*)options;
/**
* Track when a user has passed a checkpoint after the flight has taken off. Eg. passed level 1, posted high score
*
* @param checkpointName The name of the checkpoint, this should be a static string
*/
+ (void)passCheckpoint:(NSString *)checkpointName;
/**
* Opens a feedback window that is not attached to a checkpoint
*/
+ (void)openFeedbackView;
/**
* Submits custom feedback to the site. Sends the data in feedback to the site. This is to be used as the method to submit
* feedback from custom feedback forms.
*
* @param feedback Your users feedback, method does nothing if feedback is nil
*/
+ (void)submitFeedback:(NSString*)feedback;
/**
* Sets the Device Identifier.
*
* !! DO NOT CALL IN SUBMITTED APP STORE APP.
*
* !! MUST BE CALLED BEFORE +takeOff:
*
* This method should only be used during testing so that you can identify a testers test data with them.
* If you do not provide the identifier you will still see all session data, with checkpoints
* and logs, but the data will be anonymized.
*
* It is recommended that you only use this method during testing.
* Apple may reject your app if left in a submitted app.
*
* Use:
* Only use this with the Apple device UDID. DO NOT use Open ID or your own identifier.
* [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
*
* @param deviceIdentifer The current devices device identifier
*/
+ (void)setDeviceIdentifier:(NSString*)deviceIdentifer;
@end
/**
* TestFlight Option Keys
*
* Pass these as keys to the dictionary you pass to +`[TestFlight setOptions:]`.
* The values should be NSNumber BOOLs (`[NSNumber numberWithBool:YES]` or `@YES`)
*/
extern NSString *const TFOptionAttachBacktraceToFeedback; // Defaults to @NO. Setting to @YES attaches the current backtrace, with symbols, to the feedback.
extern NSString *const TFOptionDisableInAppUpdates; // Defaults to @NO. Setting to @YES, disables the in app update screen shown in BETA apps when there is a new version available on TestFlight.
extern NSString *const TFOptionLogToConsole; // Defaults to @YES. Prints remote logs to Apple System Log.
extern NSString *const TFOptionLogToSTDERR; // Defaults to @YES. Sends remote logs to STDERR when debugger is attached.
extern NSString *const TFOptionReinstallCrashHandlers; // If set to @YES: Reinstalls crash handlers, to be used if a third party library installs crash handlers overtop of the TestFlight Crash Handlers.
extern NSString *const TFOptionSendLogOnlyOnCrash; // Defaults to @NO. Setting to @YES stops remote logs from being sent when sessions end. They would only be sent in the event of a crash.

BIN
External/TestFlight/libTestFlight.a vendored Normal file

Binary file not shown.

239
External/TestFlight/release_notes.md vendored Normal file
View File

@@ -0,0 +1,239 @@
## 1.2.4 - February 19, 2013
- Fixed bug that caused crash reports to sometimes not send immediately (they would be resent later)
## 1.2.3 - January 8, 2013
- Fixed typos in readme
- Fixed bug where logs not sent on crash
- Fixed bug where empty crash files were created (but not sent)
- Cache cache path
- Use consts for `setOptions:`
- Updated `setDeviceIdentifier:` comments to make them clearer
- Remove potentially conflicting function name `UIColorFromRGB`
- Fixed crash on bad in app update data
## 1.2.2 - December 26, 2012
- Fix typo in app token error message
## 1.2.1 - December 26, 2012
- The max number of concurrent network connections has been reduced from 4 to 2.
##1.2 - November 12, 2012
* Removed Team Token support. As of version 1.2 takeOff must be called with the Application Token, https://testflightapp.com/dashboard/applications/, choose your application, select SDK, get the Token for this Application.
##1.2 BETA 3 - October 11, 2012
* Added application token support. Application Tokens are currently optional if you do not have one you do not need one
##1.2 BETA 2 - October 9, 2012
* Resolved an instance of close_file being called on a bad file descriptor
##1.2 BETA 1 - October 1, 2012
* Removed support for armv6
* Exception handler now returns instead of raising a SIGTRAP
##1.1 - September 13, 2012
* armv7s and iOS 6 support
* Updated for general release
##1.1 BETA 3 - September 12, 2012
* armv7s slice added to library
* fixed typo for in application updates, inAppUdates changed to inAppUpdates
##1.1 BETA 2 - September 6, 2012
* Re-enabled armv6 support
* Added option to disable in application updates
##1.1 BETA 1 - July 13, 2012
* Added TFLogv to allow for log customizations. Check the README or online docs for more information.
* Added option attachBacktraceToFeedback, which attaches a backtrace to feedback sent from the SDK. For users who use feedback in more than one location in the application.
* Resolved issue where other exception handlers would not be called during an exception.
* SDK now sends the device language for a session.
* Documentation fixes.
* Stability fixes.
###1.0 - March 29, 2012
* Resolved occurrences of exceptions with the message "No background task exists with identifier 0"
###1.0 BETA 1 - March 23, 2012
* Privacy Updates
* UDID is no longer collected by the SDK. During testing please use `[TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];` to send the UDID so you can identify your testers. For release do not set `+setDeviceIdentifier`. See Beta Testing and Release Differentiation in the README or online at [https://testflightapp.com/sdk/doc/1.0beta1/](http://testflightapp.com/sdk/doc/1.0beta1/)
###0.8.3 - February 14, 2012
* Rolled previous beta code into release builds
* No longer allow in application updates to occur in applications that were obtained from the app store.
**Tested compiled library with:**
* Xcode 4.3
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8.3 BETA 5 - February 10, 2012
* Changed logging from asynchronous to synchronous.
* Resolved crash when looking for a log path failed.
* Added submitFeedback to the TestFlight class to allow for custom feedback forms.
###0.8.3 BETA 4 - January 20, 2012
* Resolved an issue that occured when an application was upgraded from 0.8.3 BETA 1 to 0.8.3 BETA 3+ with unsent data from 0.8.3 BETA 1
###0.8.3 BETA 3 - January 19, 2012
* On crash log files over 64k will not be sent until next launch.
**Known Issues:**
* Logging massive amounts of data at the end of a session may prevent the application from launching in time on next launch
###0.8.3 BETA 2 - January 13, 2012
* libz.dylib is now required to be added to your "Link Binary with Libraries" build phase
* Log file compression, The compression is done on an as needed basis rather than before sending
* Changed all outgoing data from JSON to MessagePack
* Added option `logToSTDERR` to disable the `STDERR` logger
###0.8.3 BETA 1 - December 29, 2011
* In rare occurrences old session data that had not been sent to our server may have been discarded or attached to the wrong build. It is now no longer discarded
* Made sending of Session End events more robust
* Network queuing system does better bursting of unsent data
* Log files that are larger than 64K are now sent sometime after the next launch
* Log files that are larger than 16MB are no longer supported and will be replaced with a message indicating the log file was too large
* Fixed crashes while resuming from background
###0.8.2 - December 20, 2011
* Promoted 0.8.2 BETA 4 to stable
**Known Issues:**
* Under some circumstances Session End events may not be sent until the next launch.
* With large log files Session End events may take a long time to show up.
**Tested compiled library with:**
* Xcode 4.3
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8.2 BETA 4 - December 12, 2011
* Prevented "The string argument is NULL" from occuring during finishedHandshake in rare cases
* Resolved issue where data recorded while offline may not be sent
###0.8.2 BETA 3 - December 8, 2011
* Added auto-release pools to background setup and tear down
###0.8.2 BETA 2 - December 5, 2011
* Fixed the "pointer being freed was not allocated" bug
###0.8.1 - November 18, 2011
* Implemented TFLog logging system, see README for more information
* Fixed an issue where Session End events may not be sent until next launch
* Fixed an issue where duplicate events could be sent
* Fixed an issue with Session End events not being sent from some iPod touch models
**Tested compiled library with:**
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8 - November 8, 2011
* Added `SIGTRAP` as a signal type that we catch
* Removed all Objective-c from crash reporting
* Removed the use of non signal safe functions from signal handling
* Created a signal safe way to get symbols from a stack trace
* Changed the keyboardType for Long Answer Questions and Feedback to allow for international character input
* Changed `TESTFLIGHT_SDK_VERSION` string to be an `NSString`
* Changed cache folder from Library/Caches/TestFlight to Library/Caches/com.testflight.testflightsdk
* Fixed issue with saving data when device is offline
* Fixed compability issues with iOS 3
* Added calling into the rootViewController shouldAutorotateToInterfaceOrientation if a rootViewController is set
* Made the comments in TestFlight.h compatible with Appledoc
Tested compiled library with:
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2
###0.7.2 - September 29, 2011
* Changed `TESTFLIGHT_SDK_VERSION` string to be an `NSString`
* Fixed an issue where exiting an application while the SDK is active caused modal views to be dismissed
###0.7.1 - September 22, 2011
* Internal release
* Refactoring
###0.7 - September 21, 2011
* Moved TestFlight images and data to the Library/Caches folder
* Resolved an issue where sometimes the rootViewController could not be found and feedback, questions and upgrade views would not be displayed
* In application upgrade changed to allow skipping until the next version is installed and allows upgrades to be forced
* Fixed a memory leak when launching questions
###0.6 - September 2, 2011
* Renamed base64_encode to testflight_base64_encode to remove a conflict with other third party libraries
* Added ability to reinstall crash handlers when they are overwritten using the setOptions API
* Fixed an issue where crash reports might not get sent under certain circumstances
* Fixed a deadlock when the application is put in the background and then resumed before all information can be sent
* Fixed an issue when attempting to un-install all signal handlers during a signal
* Added support for landscape mode on the iPad to the Questions and Feedback views
* Crash reporting now works in versions of Xcode earlier than 4.2
* Fixed a memory leak during handshake
###0.5 - August 19, 2011
* Feedback that is not attached to a checkpoint [TestFlight openFeedbackView]
* Usability changes to question views
* Removed pause and resume sessions, replaced with sessions being stopped and started
* Added text auto correction to the Long Answer question type
* Crash reports now send on crash instead of next launch
###0.4 - August 15, 2011
* In Application Feedback with Questions
* In application updates
* Custom Environment Information added
* Networking stack reimplementation
* Exception handling fixes
###0.3 - June 15, 2011
* Removed all mention of JSONKit from the README
* Added support for using both the Bundle Version and the Bundle Short Version string
###0.2 - June 14, 2011
* Removed all categories this allows users to use the SDK without having to set -ObjC and -load_all
* Prefixed JSONKit for use in TestFlight to remove reported issues where some users were already using JSONKit
* Added support for armv6 again
###0.1 - June 11, 2011
* Initial Version

View File

@@ -1,3 +1,16 @@
2013-02-26 -- v1.2.1
- Interactive posts on Google+ share
- Improved sign-in and share APIs to use shared instances
- Automatic retrieval of user identity upon sign-in
- Expanded Google+ moments API support
- Updated sample app
2012-10-12 -- v1.1.0
- Content deep linking on Google+ share
- iOS6 support
- Shortened class names
- Bug fixes
2012-06-25 -- v1.0.0 2012-06-25 -- v1.0.0
- Google+ sign-in button, share plugin, and Google+ history integration library - Google+ sign-in button, share plugin, and Google+ history integration library
with sample app. with sample app.

View File

@@ -32,7 +32,7 @@ static NSString *EncodeBase64StringCommon(NSData *data, const char *table) {
NSUInteger bufferSize = ((length + 2) / 3) * 4; NSUInteger bufferSize = ((length + 2) / 3) * 4;
NSMutableData* buffer = [NSMutableData dataWithLength:bufferSize]; NSMutableData* buffer = [NSMutableData dataWithLength:bufferSize];
uint8_t *output = [buffer mutableBytes]; int8_t *output = [buffer mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) { for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0; NSUInteger value = 0;
@@ -70,7 +70,7 @@ static void CreateDecodingTable(const char *encodingTable,
size_t encodingTableSize, char *decodingTable) { size_t encodingTableSize, char *decodingTable) {
memset(decodingTable, 0, 128); memset(decodingTable, 0, 128);
for (unsigned int i = 0; i < encodingTableSize; i++) { for (unsigned int i = 0; i < encodingTableSize; i++) {
decodingTable[(unsigned int) encodingTable[i]] = i; decodingTable[(unsigned int) encodingTable[i]] = (char)i;
} }
} }
@@ -80,7 +80,7 @@ static NSData *DecodeBase64StringCommon(NSString *base64Str,
const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding]; const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding];
if (cString == nil) return nil; if (cString == nil) return nil;
NSUInteger inputLength = strlen(cString); NSInteger inputLength = (NSInteger)strlen(cString);
if (inputLength % 4 != 0) return nil; if (inputLength % 4 != 0) return nil;
if (inputLength == 0) return [NSData data]; if (inputLength == 0) return [NSData data];
@@ -89,7 +89,7 @@ static NSData *DecodeBase64StringCommon(NSString *base64Str,
} }
NSInteger outputLength = inputLength * 3 / 4; NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength]; NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)outputLength];
uint8_t *output = [data mutableBytes]; uint8_t *output = [data mutableBytes];
NSInteger inputPoint = 0; NSInteger inputPoint = 0;
@@ -102,12 +102,12 @@ static NSData *DecodeBase64StringCommon(NSString *base64Str,
int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0 int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0
int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A';
output[outputPoint++] = (table[i0] << 2) | (table[i1] >> 4); output[outputPoint++] = (uint8_t)((table[i0] << 2) | (table[i1] >> 4));
if (outputPoint < outputLength) { if (outputPoint < outputLength) {
output[outputPoint++] = ((table[i1] & 0xF) << 4) | (table[i2] >> 2); output[outputPoint++] = (uint8_t)(((table[i1] & 0xF) << 4) | (table[i2] >> 2));
} }
if (outputPoint < outputLength) { if (outputPoint < outputLength) {
output[outputPoint++] = ((table[i2] & 0x3) << 6) | table[i3]; output[outputPoint++] = (uint8_t)(((table[i2] & 0x3) << 6) | table[i3]);
} }
} }

View File

@@ -17,6 +17,9 @@
// GTLBatchQuery.h // GTLBatchQuery.h
// //
// Batch query documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Batch_Operations
#import "GTLQuery.h" #import "GTLQuery.h"
@interface GTLBatchQuery : NSObject <GTLQueryProtocol> { @interface GTLBatchQuery : NSObject <GTLQueryProtocol> {
@@ -42,8 +45,8 @@
+ (id)batchQuery; + (id)batchQuery;
+ (id)batchQueryWithQueries:(NSArray *)array; + (id)batchQueryWithQueries:(NSArray *)array;
- (void)addQuery:(GTLQuery *)query; - (void)addQuery:(GTLQuery *)query GTL_NONNULL((1));
- (GTLQuery *)queryForRequestID:(NSString *)requestID; - (GTLQuery *)queryForRequestID:(NSString *)requestID GTL_NONNULL((1));
@end @end

View File

@@ -16,6 +16,9 @@
// //
// GTLDateTime.h // GTLDateTime.h
// //
// This is an immutable class representing a date and optionally a
// time with time zone.
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "GTLDefines.h" #import "GTLDefines.h"
@@ -28,14 +31,16 @@
NSTimeZone *timeZone_; // specific time zone by name, if known NSTimeZone *timeZone_; // specific time zone by name, if known
} }
// Note: nil can be passed for time zone arguments when the time zone is not
// known.
+ (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str; + (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str;
// timeZone may be nil if the time zone is not known.
+ (GTLDateTime *)dateTimeWithDate:(NSDate *)date timeZone:(NSTimeZone *)tz; + (GTLDateTime *)dateTimeWithDate:(NSDate *)date timeZone:(NSTimeZone *)tz;
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz; // Use this method to make a dateTime for an all-day event (date only, so
- (void)setFromRFC3339String:(NSString *)str; // hasTime is NO.)
+ (GTLDateTime *)dateTimeForAllDayWithDate:(NSDate *)date;
+ (GTLDateTime *)dateTimeWithDateComponents:(NSDateComponents *)date;
@property (nonatomic, readonly) NSDate *date; @property (nonatomic, readonly) NSDate *date;
@property (nonatomic, readonly) NSCalendar *calendar; @property (nonatomic, readonly) NSCalendar *calendar;
@@ -43,14 +48,13 @@
@property (nonatomic, readonly) NSString *RFC3339String; @property (nonatomic, readonly) NSString *RFC3339String;
@property (nonatomic, readonly) NSString *stringValue; // same as RFC3339String @property (nonatomic, readonly) NSString *stringValue; // same as RFC3339String
@property (nonatomic, retain) NSTimeZone *timeZone; @property (nonatomic, readonly, retain) NSTimeZone *timeZone;
@property (nonatomic, copy) NSDateComponents *dateComponents; @property (nonatomic, readonly, copy) NSDateComponents *dateComponents;
@property (nonatomic, assign) NSInteger milliseconds; // This is only for the fraction of a second 0-999 @property (nonatomic, readonly) NSInteger milliseconds; // This is only for the fraction of a second 0-999
@property (nonatomic, assign) BOOL hasTime; @property (nonatomic, readonly) BOOL hasTime;
@property (nonatomic, assign) NSInteger offsetSeconds; @property (nonatomic, readonly) NSInteger offsetSeconds;
@property (nonatomic, assign, getter=isUniversalTime) BOOL universalTime; @property (nonatomic, readonly, getter=isUniversalTime) BOOL universalTime;
- (void)setTimeZone:(NSTimeZone *)timeZone withOffsetSeconds:(NSInteger)val;
@end @end

View File

@@ -19,6 +19,26 @@
#import "GTLDateTime.h" #import "GTLDateTime.h"
@interface GTLDateTime ()
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz;
- (void)setFromRFC3339String:(NSString *)str;
@property (nonatomic, retain, readwrite) NSTimeZone *timeZone;
@property (nonatomic, copy, readwrite) NSDateComponents *dateComponents;
@property (nonatomic, assign, readwrite) NSInteger milliseconds;
@property (nonatomic, assign, readwrite) BOOL hasTime;
@property (nonatomic, assign, readwrite) NSInteger offsetSeconds;
@property (nonatomic, assign, getter=isUniversalTime, readwrite) BOOL universalTime;
@end
static NSCharacterSet *gDashSet = nil;
static NSCharacterSet *gTSet = nil;
static NSCharacterSet *gColonSet = nil;
static NSCharacterSet *gPlusMinusZSet = nil;
static NSMutableDictionary *gCalendarsForTimeZones = nil;
@implementation GTLDateTime @implementation GTLDateTime
@@ -44,6 +64,19 @@
offsetSeconds = offsetSeconds_, offsetSeconds = offsetSeconds_,
universalTime = isUniversalTime_; universalTime = isUniversalTime_;
+ (void)initialize {
// Note that initialize is guaranteed by the runtime to be called in a
// thread-safe manner.
if (gDashSet == nil) {
gDashSet = [[NSCharacterSet characterSetWithCharactersInString:@"-"] retain];
gTSet = [[NSCharacterSet characterSetWithCharactersInString:@"Tt "] retain];
gColonSet = [[NSCharacterSet characterSetWithCharactersInString:@":"] retain];
gPlusMinusZSet = [[NSCharacterSet characterSetWithCharactersInString:@"+-zZ"] retain];
gCalendarsForTimeZones = [[NSMutableDictionary alloc] init];
}
}
+ (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str { + (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str {
if (str == nil) return nil; if (str == nil) return nil;
@@ -60,6 +93,30 @@
return result; return result;
} }
+ (GTLDateTime *)dateTimeForAllDayWithDate:(NSDate *)date {
if (date == nil) return nil;
GTLDateTime *result = [[[self alloc] init] autorelease];
[result setFromDate:date timeZone:nil];
result.hasTime = NO;
return result;
}
+ (GTLDateTime *)dateTimeWithDateComponents:(NSDateComponents *)components {
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDate *date = [cal dateFromComponents:components];
#if GTL_IPHONE
NSTimeZone *tz = [components timeZone];
#else
// NSDateComponents added timeZone: in Mac OS X 10.7.
NSTimeZone *tz = nil;
if ([components respondsToSelector:@selector(timeZone)]) {
tz = [components timeZone];
}
#endif
return [self dateTimeWithDate:date timeZone:tz];
}
- (void)dealloc { - (void)dealloc {
[dateComponents_ release]; [dateComponents_ release];
[timeZone_ release]; [timeZone_ release];
@@ -67,15 +124,8 @@
} }
- (id)copyWithZone:(NSZone *)zone { - (id)copyWithZone:(NSZone *)zone {
// Object is immutable
GTLDateTime *newObj = [[GTLDateTime alloc] init]; return [self retain];
newObj.universalTime = self.isUniversalTime;
[newObj setTimeZone:self.timeZone withOffsetSeconds:self.offsetSeconds];
newObj.dateComponents = self.dateComponents;
newObj.milliseconds = self.milliseconds;
return newObj;
} }
// until NSDateComponent implements isEqual, we'll use this // until NSDateComponent implements isEqual, we'll use this
@@ -148,36 +198,41 @@
} }
} }
- (void)setTimeZone:(NSTimeZone *)timeZone withOffsetSeconds:(NSInteger)val { - (NSCalendar *)calendarForTimeZone:(NSTimeZone *)tz {
[timeZone_ release]; NSCalendar *cal = nil;
timeZone_ = [timeZone retain]; @synchronized(gCalendarsForTimeZones) {
id tzKey = (tz ? tz : [NSNull null]);
offsetSeconds_ = val; cal = [gCalendarsForTimeZones objectForKey:tzKey];
} if (cal == nil) {
cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
- (NSCalendar *)calendar { if (tz) {
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; [cal setTimeZone:tz];
NSTimeZone *tz = self.timeZone; }
if (tz) { [gCalendarsForTimeZones setObject:cal forKey:tzKey];
[cal setTimeZone:tz]; }
} }
return cal; return cal;
} }
- (NSCalendar *)calendar {
NSTimeZone *tz = self.timeZone;
return [self calendarForTimeZone:tz];
}
- (NSDate *)date { - (NSDate *)date {
NSCalendar *cal = self.calendar;
NSDateComponents *dateComponents = self.dateComponents; NSDateComponents *dateComponents = self.dateComponents;
NSTimeInterval extraMillisecondsAsSeconds = 0.0; NSTimeInterval extraMillisecondsAsSeconds = 0.0;
NSCalendar *cal;
if (!self.hasTime) { if (!self.hasTime) {
// we're not keeping track of a time, but NSDate always is based on // We're not keeping track of a time, but NSDate always is based on
// an absolute time. We want to avoid returning an NSDate where the // an absolute time. We want to avoid returning an NSDate where the
// calendar date appears different from what was used to create our // calendar date appears different from what was used to create our
// date-time object. // date-time object.
// //
// We'll make a copy of the date components, setting the time on our // We'll make a copy of the date components, setting the time on our
// copy to noon GMT, since that ensures the date renders correctly for // copy to noon GMT, since that ensures the date renders correctly for
// any time zone // any time zone.
NSDateComponents *noonDateComponents = [[dateComponents copy] autorelease]; NSDateComponents *noonDateComponents = [[dateComponents copy] autorelease];
[noonDateComponents setHour:12]; [noonDateComponents setHour:12];
[noonDateComponents setMinute:0]; [noonDateComponents setMinute:0];
@@ -185,8 +240,10 @@
dateComponents = noonDateComponents; dateComponents = noonDateComponents;
NSTimeZone *gmt = [NSTimeZone timeZoneWithName:@"Universal"]; NSTimeZone *gmt = [NSTimeZone timeZoneWithName:@"Universal"];
[cal setTimeZone:gmt]; cal = [self calendarForTimeZone:gmt];
} else { } else {
cal = self.calendar;
// Add in the fractional seconds that don't fit into NSDateComponents. // Add in the fractional seconds that don't fit into NSDateComponents.
extraMillisecondsAsSeconds = ((NSTimeInterval)self.milliseconds) / 1000.0; extraMillisecondsAsSeconds = ((NSTimeInterval)self.milliseconds) / 1000.0;
} }
@@ -254,10 +311,7 @@
} }
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz { - (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz {
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; NSCalendar *cal = [self calendarForTimeZone:tz];
if (tz) {
[cal setTimeZone:tz];
}
NSUInteger const kComponentBits = (NSYearCalendarUnit | NSMonthCalendarUnit NSUInteger const kComponentBits = (NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit
@@ -308,25 +362,20 @@
// There should be no whitespace, so no skip characters. // There should be no whitespace, so no skip characters.
[scanner setCharactersToBeSkipped:nil]; [scanner setCharactersToBeSkipped:nil];
NSCharacterSet* dashSet = [NSCharacterSet characterSetWithCharactersInString:@"-"];
NSCharacterSet* tSet = [NSCharacterSet characterSetWithCharactersInString:@"Tt "];
NSCharacterSet* colonSet = [NSCharacterSet characterSetWithCharactersInString:@":"];
NSCharacterSet* plusMinusZSet = [NSCharacterSet characterSetWithCharactersInString:@"+-zZ"];
// for example, scan 2006-11-17T15:10:46-08:00 // for example, scan 2006-11-17T15:10:46-08:00
// or 2006-11-17T15:10:46Z // or 2006-11-17T15:10:46Z
if (// yyyy-mm-dd if (// yyyy-mm-dd
[scanner scanInteger:&year] && [scanner scanInteger:&year] &&
[scanner scanCharactersFromSet:dashSet intoString:NULL] && [scanner scanCharactersFromSet:gDashSet intoString:NULL] &&
[scanner scanInteger:&month] && [scanner scanInteger:&month] &&
[scanner scanCharactersFromSet:dashSet intoString:NULL] && [scanner scanCharactersFromSet:gDashSet intoString:NULL] &&
[scanner scanInteger:&day] && [scanner scanInteger:&day] &&
// Thh:mm:ss // Thh:mm:ss
[scanner scanCharactersFromSet:tSet intoString:NULL] && [scanner scanCharactersFromSet:gTSet intoString:NULL] &&
[scanner scanInteger:&hour] && [scanner scanInteger:&hour] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] && [scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
[scanner scanInteger:&minute] && [scanner scanInteger:&minute] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] && [scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
[scanner scanDouble:&secDouble]) { [scanner scanDouble:&secDouble]) {
// At this point we got secDouble, pull it apart. // At this point we got secDouble, pull it apart.
@@ -336,9 +385,9 @@
// Finish parsing, now the offset info. // Finish parsing, now the offset info.
if (// Z or +hh:mm if (// Z or +hh:mm
[scanner scanCharactersFromSet:plusMinusZSet intoString:&sign] && [scanner scanCharactersFromSet:gPlusMinusZSet intoString:&sign] &&
[scanner scanInteger:&offsetHour] && [scanner scanInteger:&offsetHour] &&
[scanner scanCharactersFromSet:colonSet intoString:NULL] && [scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
[scanner scanInteger:&offsetMinute]) { [scanner scanInteger:&offsetMinute]) {
} }
} }

View File

@@ -126,3 +126,19 @@
#define NS_RETURNS_NOT_RETAINED #define NS_RETURNS_NOT_RETAINED
#endif #endif
#endif #endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if 1
// We will start using nonnull declarations once the static analyzer seems
// to support it without false positives.
#define GTL_NONNULL(x)
#else
#if __has_attribute(nonnull)
#define GTL_NONNULL(x) __attribute__((nonnull x))
#else
#define GTL_NONNULL(x)
#endif
#endif

View File

@@ -17,6 +17,8 @@
// GTLObject.h // GTLObject.h
// //
// GTLObject documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Objects_and_Queries
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -51,7 +53,7 @@
// Used when creating the subobjects from this one. // Used when creating the subobjects from this one.
NSDictionary *surrogates_; NSDictionary *surrogates_;
// Any complex object hung off this object goes into the cache so the // Any complex object hung off this object goes into the cache so the
// next fetch will get the same object back instead of having to recreate // next fetch will get the same object back instead of having to recreate
// it. // it.
@@ -81,7 +83,7 @@
- (NSString *)JSONString; - (NSString *)JSONString;
// generic access to json; also creates it if necessary // generic access to json; also creates it if necessary
- (void)setJSONValue:(id)obj forKey:(NSString *)key; - (void)setJSONValue:(id)obj forKey:(NSString *)key GTL_NONNULL((2));
- (id)JSONValueForKey:(NSString *)key; - (id)JSONValueForKey:(NSString *)key;
// Returns the list of keys in this object's JSON that aren't listed as // Returns the list of keys in this object's JSON that aren't listed as
@@ -91,13 +93,15 @@
// Any keys in the JSON that aren't listed as @properties on the object // Any keys in the JSON that aren't listed as @properties on the object
// are counted as "additional properties". These allow you to get/set them. // are counted as "additional properties". These allow you to get/set them.
- (id)additionalPropertyForName:(NSString *)name; - (id)additionalPropertyForName:(NSString *)name;
- (void)setAdditionalProperty:(id)obj forName:(NSString *)name; - (void)setAdditionalProperty:(id)obj forName:(NSString *)name GTL_NONNULL((2));
- (NSDictionary *)additionalProperties; - (NSDictionary *)additionalProperties;
// User properties are supported for client convenience, but are not copied by // User properties are supported for client convenience, but are not copied by
// copyWithZone. User Properties keys beginning with _ are reserved by the library. // copyWithZone. User Properties keys beginning with _ are reserved by the library.
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property //
- (id)propertyForKey:(NSString *)key; // Set nil for obj to remove the property.
- (void)setProperty:(id)obj forKey:(NSString *)key GTL_NONNULL((2));
- (id)propertyForKey:(NSString *)key GTL_NONNULL((1));
// userData is stored as a property with key "_userData" // userData is stored as a property with key "_userData"
- (void)setUserData:(id)obj; - (void)setUserData:(id)obj;
@@ -156,15 +160,39 @@
@end @end
// Collection objects with an "items" property should derive from GTLCollection // Collection objects with an "items" property should derive from GTLCollection
// object. This provides support for fast object enumeration and the // object. This provides support for fast object enumeration, the
// itemAtIndex: convenience method. // itemAtIndex: convenience method, and indexed subscripts.
// //
// Subclasses must implement the items method dynamically. // Subclasses must implement the items method dynamically.
@interface GTLCollectionObject : GTLObject <GTLCollectionProtocol, NSFastEnumeration> @interface GTLCollectionObject : GTLObject <GTLCollectionProtocol, NSFastEnumeration> {
@private
NSDictionary *identifierMap_;
}
// itemAtIndex: returns nil when the index exceeds the bounds of the items array // itemAtIndex: and objectAtIndexedSubscript: return nil when the index exceeds
// the bounds of the items array.
- (id)itemAtIndex:(NSUInteger)idx; - (id)itemAtIndex:(NSUInteger)idx;
- (id)objectAtIndexedSubscript:(NSInteger)idx;
// itemForIdentifier: looks up items from the collection object by identifier,
// and returns the first one.
//
// Typically, items will have a unique identifier (with key "id" in the
// object's JSON). This method returns the first item found in the collection
// with the specified identifier.
//
// The first time this method is used, the collection will cache a map of
// identifiers to items. If the items list for the instance somehow changes,
// use the reset method below to force a new cache to be created for this
// collection.
- (id)itemForIdentifier:(NSString *)key GTL_NONNULL((1));
// Identifiers for all items are cached when the first one is obtained.
// This method resets the cache. It is needed only if the item list has
// changed.
- (void)resetIdentifierMap;
@end @end
@interface GTLCollectionObject (DynamicMethods) @interface GTLCollectionObject (DynamicMethods)
@@ -173,7 +201,7 @@
// Base object use for when an service method directly returns an array instead // Base object use for when an service method directly returns an array instead
// of an object. Normally methods should return an object with an 'items' // of an object. Normally methods should return an object with an 'items'
// property, this exists for the methods not up to spec. // property, but this exists for the methods not up to spec.
@interface GTLResultArray : GTLCollectionObject @interface GTLResultArray : GTLCollectionObject
// This method should only be called by subclasses. // This method should only be called by subclasses.
- (NSArray *)itemsWithItemClass:(Class)itemClass; - (NSArray *)itemsWithItemClass:(Class)itemClass;

View File

@@ -197,7 +197,7 @@ static NSString *const kUserDataPropertyKey = @"_userData";
// Open question: should this instead create the union of elements for // Open question: should this instead create the union of elements for
// all items in the array, rather than just get fields from the first // all items in the array, rather than just get fields from the first
// array object? // array object?
if ([value count] > 0) { if ([(NSArray *)value count] > 0) {
id firstObj = [value objectAtIndex:0]; id firstObj = [value objectAtIndex:0];
if ([firstObj isKindOfClass:[NSDictionary class]]) { if ([firstObj isKindOfClass:[NSDictionary class]]) {
// An array of objects // An array of objects
@@ -455,7 +455,7 @@ static NSString *const kUserDataPropertyKey = @"_userData";
} else if ([rawValue isKindOfClass:[NSArray class]]) { } else if ([rawValue isKindOfClass:[NSArray class]]) {
// for arrays, show the number of items in the array: // for arrays, show the number of items in the array:
// [3] // [3]
value = [NSString stringWithFormat:@"[%lu]", (unsigned long)[rawValue count]]; value = [NSString stringWithFormat:@"[%lu]", (unsigned long)[(NSArray *)rawValue count]];
} else if ([rawValue isKindOfClass:[NSString class]]) { } else if ([rawValue isKindOfClass:[NSString class]]) {
// for strings, show the string in quotes: // for strings, show the string in quotes:
// "Hi mom." // "Hi mom."
@@ -516,14 +516,11 @@ static NSMutableDictionary *gKindMap = nil;
defaultClass:(Class)defaultClass defaultClass:(Class)defaultClass
surrogates:(NSDictionary *)surrogates surrogates:(NSDictionary *)surrogates
batchClassMap:(NSDictionary *)batchClassMap { batchClassMap:(NSDictionary *)batchClassMap {
if ([json isEqual:[NSNull null]]) { if ([json count] == 0 || [json isEqual:[NSNull null]]) {
// no actual result, such as the response from a delete // no actual result, such as the response from a delete
return nil; return nil;
} }
GTL_ASSERT([json count] != 0, @"Creating object from empty json");
if ([json count] == 0) return nil;
// Determine the class to instantiate, based on the original fetch // Determine the class to instantiate, based on the original fetch
// request or by looking up "kind" string from the registration at // request or by looking up "kind" string from the registration at
// +load time of GTLObject subclasses // +load time of GTLObject subclasses
@@ -629,9 +626,13 @@ static NSMutableDictionary *gArrayPropertyToClassMapCache = nil;
@end @end
@implementation GTLCollectionObject @implementation GTLCollectionObject
// Subclasses must implement the items method dynamically. // Subclasses must implement the items method dynamically.
- (void)dealloc {
[identifierMap_ release];
[super dealloc];
}
- (id)itemAtIndex:(NSUInteger)idx { - (id)itemAtIndex:(NSUInteger)idx {
NSArray *items = [self performSelector:@selector(items)]; NSArray *items = [self performSelector:@selector(items)];
if (idx < [items count]) { if (idx < [items count]) {
@@ -640,6 +641,36 @@ static NSMutableDictionary *gArrayPropertyToClassMapCache = nil;
return nil; return nil;
} }
- (id)objectAtIndexedSubscript:(NSInteger)idx {
if (idx >= 0) {
return [self itemAtIndex:(NSUInteger)idx];
}
return nil;
}
- (id)itemForIdentifier:(NSString *)key {
if (identifierMap_ == nil) {
NSArray *items = [self performSelector:@selector(items)];
NSMutableDictionary *dict =
[NSMutableDictionary dictionaryWithCapacity:[items count]];
for (id item in items) {
id identifier = [item valueForKey:@"identifier"];
if (identifier != nil && identifier != [NSNull null]) {
if ([dict objectForKey:identifier] == nil) {
[dict setObject:item forKey:identifier];
}
}
}
identifierMap_ = [dict copy];
}
return [identifierMap_ objectForKey:key];
}
- (void)resetIdentifierMap {
[identifierMap_ release];
identifierMap_ = nil;
}
// NSFastEnumeration protocol // NSFastEnumeration protocol
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id *)stackbuf objects:(id *)stackbuf

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,16 +20,24 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
#import "GTLPlusConstants.h" #import "GTLPlusConstants.h"
#import "GTLPlusAcl.h"
#import "GTLPlusAclentryResource.h"
#import "GTLPlusActivity.h"
#import "GTLPlusActivityFeed.h"
#import "GTLPlusComment.h"
#import "GTLPlusCommentFeed.h"
#import "GTLPlusItemScope.h" #import "GTLPlusItemScope.h"
#import "GTLPlusMoment.h" #import "GTLPlusMoment.h"
#import "GTLPlusMomentsFeed.h"
#import "GTLPlusPeopleFeed.h"
#import "GTLPlusPerson.h" #import "GTLPlusPerson.h"
#import "GTLQueryPlus.h" #import "GTLQueryPlus.h"

View File

@@ -0,0 +1,60 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusAcl.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusAcl (0 custom class methods, 3 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusAclentryResource;
// ----------------------------------------------------------------------------
//
// GTLPlusAcl
//
// This class supports NSFastEnumeration over its "items" property. It also
// supports -itemAtIndex: to retrieve individual objects from "items".
@interface GTLPlusAcl : GTLCollectionObject
// Description of the access granted, suitable for display.
// Remapped to 'descriptionProperty' to avoid NSObject's 'description'.
@property (copy) NSString *descriptionProperty;
// The list of access entries.
@property (retain) NSArray *items; // of GTLPlusAclentryResource
// Identifies this resource as a collection of access controls. Value:
// "plus#acl".
@property (copy) NSString *kind;
@end

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusAcl.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusAcl (0 custom class methods, 3 custom properties)
#import "GTLPlusAcl.h"
#import "GTLPlusAclentryResource.h"
// ----------------------------------------------------------------------------
//
// GTLPlusAcl
//
@implementation GTLPlusAcl
@dynamic descriptionProperty, items, kind;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"description"
forKey:@"descriptionProperty"];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusAclentryResource class]
forKey:@"items"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#acl"];
}
@end

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusAclentryResource.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusAclentryResource (0 custom class methods, 3 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
// ----------------------------------------------------------------------------
//
// GTLPlusAclentryResource
//
@interface GTLPlusAclentryResource : GTLObject
// A descriptive name for this entry. Suitable for display.
@property (copy) NSString *displayName;
// The ID of the entry. For entries of type "person" or "circle", this is the ID
// of the resource. For other types, this property is not set.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The type of entry describing to whom access is granted. Possible values are:
// - "person" - Access to an individual.
// - "circle" - Access to members of a circle.
// - "myCircles" - Access to members of all the person's circles.
// - "extendedCircles" - Access to members of everyone in a person's circles,
// plus all of the people in their circles.
// - "public" - Access to anyone on the web.
@property (copy) NSString *type;
@end

View File

@@ -0,0 +1,48 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusAclentryResource.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusAclentryResource (0 custom class methods, 3 custom properties)
#import "GTLPlusAclentryResource.h"
// ----------------------------------------------------------------------------
//
// GTLPlusAclentryResource
//
@implementation GTLPlusAclentryResource
@dynamic displayName, identifier, type;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
@end

View File

@@ -0,0 +1,493 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusActivity.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusActivity (0 custom class methods, 19 custom properties)
// GTLPlusActivityActor (0 custom class methods, 5 custom properties)
// GTLPlusActivityObject (0 custom class methods, 10 custom properties)
// GTLPlusActivityProvider (0 custom class methods, 1 custom properties)
// GTLPlusActivityActorImage (0 custom class methods, 1 custom properties)
// GTLPlusActivityActorName (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectActor (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItem (0 custom class methods, 9 custom properties)
// GTLPlusActivityObjectPlusoners (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectReplies (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectResharers (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectActorImage (0 custom class methods, 1 custom properties)
// GTLPlusActivityObjectAttachmentsItemEmbed (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectAttachmentsItemFullImage (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItemImage (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItemThumbnailsItem (0 custom class methods, 3 custom properties)
// GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage (0 custom class methods, 4 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusAcl;
@class GTLPlusActivityActor;
@class GTLPlusActivityActorImage;
@class GTLPlusActivityActorName;
@class GTLPlusActivityObject;
@class GTLPlusActivityObjectActor;
@class GTLPlusActivityObjectActorImage;
@class GTLPlusActivityObjectAttachmentsItem;
@class GTLPlusActivityObjectAttachmentsItemEmbed;
@class GTLPlusActivityObjectAttachmentsItemFullImage;
@class GTLPlusActivityObjectAttachmentsItemImage;
@class GTLPlusActivityObjectAttachmentsItemThumbnailsItem;
@class GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage;
@class GTLPlusActivityObjectPlusoners;
@class GTLPlusActivityObjectReplies;
@class GTLPlusActivityObjectResharers;
@class GTLPlusActivityProvider;
// ----------------------------------------------------------------------------
//
// GTLPlusActivity
//
@interface GTLPlusActivity : GTLObject
// Identifies who has access to see this activity.
@property (retain) GTLPlusAcl *access;
// The person who performed this activity.
@property (retain) GTLPlusActivityActor *actor;
// Street address where this activity occurred.
@property (copy) NSString *address;
// Additional content added by the person who shared this activity, applicable
// only when resharing an activity.
@property (copy) NSString *annotation;
// If this activity is a crosspost from another system, this property specifies
// the ID of the original activity.
@property (copy) NSString *crosspostSource;
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// Latitude and longitude where this activity occurred. Format is latitude
// followed by longitude, space separated.
@property (copy) NSString *geocode;
// The ID of this activity.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// Identifies this resource as an activity. Value: "plus#activity".
@property (copy) NSString *kind;
// The object of this activity.
@property (retain) GTLPlusActivityObject *object;
// ID of the place where this activity occurred.
@property (copy) NSString *placeId;
// Name of the place where this activity occurred.
@property (copy) NSString *placeName;
// The service provider that initially published this activity.
@property (retain) GTLPlusActivityProvider *provider;
// The time at which this activity was initially published. Formatted as an RFC
// 3339 timestamp.
@property (retain) GTLDateTime *published;
// Radius, in meters, of the region where this activity occurred, centered at
// the latitude and longitude identified in geocode.
@property (copy) NSString *radius;
// Title of this activity.
@property (copy) NSString *title;
// The time at which this activity was last updated. Formatted as an RFC 3339
// timestamp.
@property (retain) GTLDateTime *updated;
// The link to this activity.
@property (copy) NSString *url;
// This activity's verb, indicating what action was performed. Possible values
// are:
// - "post" - Publish content to the stream.
// - "share" - Reshare an activity.
@property (copy) NSString *verb;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActor
//
@interface GTLPlusActivityActor : GTLObject
// The name of the actor, suitable for display.
@property (copy) NSString *displayName;
// The ID of the actor's person resource.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The image representation of the actor.
@property (retain) GTLPlusActivityActorImage *image;
// An object representation of the individual components of name.
@property (retain) GTLPlusActivityActorName *name;
// The link to the actor's Google profile.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObject
//
@interface GTLPlusActivityObject : GTLObject
// If this activity's object is itself another activity (for example, when a
// person reshares an activity), this property specifies the original activity's
// actor.
@property (retain) GTLPlusActivityObjectActor *actor;
// The media objects attached to this activity.
@property (retain) NSArray *attachments; // of GTLPlusActivityObjectAttachmentsItem
// The HTML-formatted content, suitable for display.
@property (copy) NSString *content;
// The ID of the object. When resharing an activity, this is the ID of the
// activity being reshared.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The type of the object. Possible values are:
// - "note" - Textual content.
// - "activity" - A Google+ activity.
@property (copy) NSString *objectType;
// The content (text) as provided by the author, stored without any HTML
// formatting. When creating or updating an activity, this value must be
// supplied as plain text in the request.
@property (copy) NSString *originalContent;
// People who +1'd this activity.
@property (retain) GTLPlusActivityObjectPlusoners *plusoners;
// Comments in reply to this activity.
@property (retain) GTLPlusActivityObjectReplies *replies;
// People who reshared this activity.
@property (retain) GTLPlusActivityObjectResharers *resharers;
// The URL that points to the linked resource.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityProvider
//
@interface GTLPlusActivityProvider : GTLObject
// Name of the service provider.
@property (copy) NSString *title;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActorImage
//
@interface GTLPlusActivityActorImage : GTLObject
// The URL of the actor's profile photo. To re-size the image and crop it to a
// square, append the query string ?sz=x, where x is the dimension in pixels of
// each side.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActorName
//
@interface GTLPlusActivityActorName : GTLObject
// The family name (last name) of the actor.
@property (copy) NSString *familyName;
// The given name (first name) of the actor.
@property (copy) NSString *givenName;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectActor
//
@interface GTLPlusActivityObjectActor : GTLObject
// The original actor's name, suitable for display.
@property (copy) NSString *displayName;
// ID of the original actor.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The image representation of the original actor.
@property (retain) GTLPlusActivityObjectActorImage *image;
// A link to the original actor's Google profile.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItem
//
@interface GTLPlusActivityObjectAttachmentsItem : GTLObject
// If the attachment is an article, this property contains a snippet of text
// from the article. It can also include descriptions for other types.
@property (copy) NSString *content;
// The title of the attachment (such as a photo caption or an article title).
@property (copy) NSString *displayName;
// If the attachment is a video, the embeddable link.
@property (retain) GTLPlusActivityObjectAttachmentsItemEmbed *embed;
// The full image URL for photo attachments.
@property (retain) GTLPlusActivityObjectAttachmentsItemFullImage *fullImage;
// The ID of the attachment.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The preview image for photos or videos.
@property (retain) GTLPlusActivityObjectAttachmentsItemImage *image;
// The type of media object. Possible values are:
// - "photo" - A photo.
// - "album" - A photo album.
// - "video" - A video.
// - "article" - An article, specified by a link.
@property (copy) NSString *objectType;
// If the attachment is an album, potential additional thumbnails from the
// album.
@property (retain) NSArray *thumbnails; // of GTLPlusActivityObjectAttachmentsItemThumbnailsItem
// The link to the attachment, should be of type text/html.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectPlusoners
//
@interface GTLPlusActivityObjectPlusoners : GTLObject
// The URL for the collection of people who +1'd this activity.
@property (copy) NSString *selfLink;
// Total number of people who +1'd this activity.
@property (retain) NSNumber *totalItems; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectReplies
//
@interface GTLPlusActivityObjectReplies : GTLObject
// The URL for the collection of comments in reply to this activity.
@property (copy) NSString *selfLink;
// Total number of comments on this activity.
@property (retain) NSNumber *totalItems; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectResharers
//
@interface GTLPlusActivityObjectResharers : GTLObject
// The URL for the collection of resharers.
@property (copy) NSString *selfLink;
// Total number of people who reshared this activity.
@property (retain) NSNumber *totalItems; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectActorImage
//
@interface GTLPlusActivityObjectActorImage : GTLObject
// A URL that points to a thumbnail photo of the original actor.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemEmbed
//
@interface GTLPlusActivityObjectAttachmentsItemEmbed : GTLObject
// Media type of the link.
@property (copy) NSString *type;
// URL of the link.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemFullImage
//
@interface GTLPlusActivityObjectAttachmentsItemFullImage : GTLObject
// The height, in pixels, of the linked resource.
@property (retain) NSNumber *height; // unsignedIntValue
// Media type of the link.
@property (copy) NSString *type;
// URL to the image.
@property (copy) NSString *url;
// The width, in pixels, of the linked resource.
@property (retain) NSNumber *width; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemImage
//
@interface GTLPlusActivityObjectAttachmentsItemImage : GTLObject
// The height, in pixels, of the linked resource.
@property (retain) NSNumber *height; // unsignedIntValue
// Media type of the link.
@property (copy) NSString *type;
// Image url.
@property (copy) NSString *url;
// The width, in pixels, of the linked resource.
@property (retain) NSNumber *width; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemThumbnailsItem
//
@interface GTLPlusActivityObjectAttachmentsItemThumbnailsItem : GTLObject
// Potential name of the thumbnail.
// Remapped to 'descriptionProperty' to avoid NSObject's 'description'.
@property (copy) NSString *descriptionProperty;
// Image resource.
@property (retain) GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage *image;
// URL to the webpage containing the image.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage
//
@interface GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage : GTLObject
// The height, in pixels, of the linked resource.
@property (retain) NSNumber *height; // unsignedIntValue
// Media type of the link.
@property (copy) NSString *type;
// Image url.
@property (copy) NSString *url;
// The width, in pixels, of the linked resource.
@property (retain) NSNumber *width; // unsignedIntValue
@end

View File

@@ -0,0 +1,290 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusActivity.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusActivity (0 custom class methods, 19 custom properties)
// GTLPlusActivityActor (0 custom class methods, 5 custom properties)
// GTLPlusActivityObject (0 custom class methods, 10 custom properties)
// GTLPlusActivityProvider (0 custom class methods, 1 custom properties)
// GTLPlusActivityActorImage (0 custom class methods, 1 custom properties)
// GTLPlusActivityActorName (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectActor (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItem (0 custom class methods, 9 custom properties)
// GTLPlusActivityObjectPlusoners (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectReplies (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectResharers (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectActorImage (0 custom class methods, 1 custom properties)
// GTLPlusActivityObjectAttachmentsItemEmbed (0 custom class methods, 2 custom properties)
// GTLPlusActivityObjectAttachmentsItemFullImage (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItemImage (0 custom class methods, 4 custom properties)
// GTLPlusActivityObjectAttachmentsItemThumbnailsItem (0 custom class methods, 3 custom properties)
// GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage (0 custom class methods, 4 custom properties)
#import "GTLPlusActivity.h"
#import "GTLPlusAcl.h"
// ----------------------------------------------------------------------------
//
// GTLPlusActivity
//
@implementation GTLPlusActivity
@dynamic access, actor, address, annotation, crosspostSource, ETag, geocode,
identifier, kind, object, placeId, placeName, provider, published,
radius, title, updated, url, verb;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"etag", @"ETag",
@"id", @"identifier",
nil];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#activity"];
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActor
//
@implementation GTLPlusActivityActor
@dynamic displayName, identifier, image, name, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObject
//
@implementation GTLPlusActivityObject
@dynamic actor, attachments, content, identifier, objectType, originalContent,
plusoners, replies, resharers, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusActivityObjectAttachmentsItem class]
forKey:@"attachments"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityProvider
//
@implementation GTLPlusActivityProvider
@dynamic title;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActorImage
//
@implementation GTLPlusActivityActorImage
@dynamic url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityActorName
//
@implementation GTLPlusActivityActorName
@dynamic familyName, givenName;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectActor
//
@implementation GTLPlusActivityObjectActor
@dynamic displayName, identifier, image, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItem
//
@implementation GTLPlusActivityObjectAttachmentsItem
@dynamic content, displayName, embed, fullImage, identifier, image, objectType,
thumbnails, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusActivityObjectAttachmentsItemThumbnailsItem class]
forKey:@"thumbnails"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectPlusoners
//
@implementation GTLPlusActivityObjectPlusoners
@dynamic selfLink, totalItems;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectReplies
//
@implementation GTLPlusActivityObjectReplies
@dynamic selfLink, totalItems;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectResharers
//
@implementation GTLPlusActivityObjectResharers
@dynamic selfLink, totalItems;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectActorImage
//
@implementation GTLPlusActivityObjectActorImage
@dynamic url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemEmbed
//
@implementation GTLPlusActivityObjectAttachmentsItemEmbed
@dynamic type, url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemFullImage
//
@implementation GTLPlusActivityObjectAttachmentsItemFullImage
@dynamic height, type, url, width;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemImage
//
@implementation GTLPlusActivityObjectAttachmentsItemImage
@dynamic height, type, url, width;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemThumbnailsItem
//
@implementation GTLPlusActivityObjectAttachmentsItemThumbnailsItem
@dynamic descriptionProperty, image, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"description"
forKey:@"descriptionProperty"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage
//
@implementation GTLPlusActivityObjectAttachmentsItemThumbnailsItemImage
@dynamic height, type, url, width;
@end

View File

@@ -0,0 +1,81 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusActivityFeed.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusActivityFeed (0 custom class methods, 9 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusActivity;
// ----------------------------------------------------------------------------
//
// GTLPlusActivityFeed
//
// This class supports NSFastEnumeration over its "items" property. It also
// supports -itemAtIndex: to retrieve individual objects from "items".
@interface GTLPlusActivityFeed : GTLCollectionObject
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The ID of this collection of activities. Deprecated.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The activities in this page of results.
@property (retain) NSArray *items; // of GTLPlusActivity
// Identifies this resource as a collection of activities. Value:
// "plus#activityFeed".
@property (copy) NSString *kind;
// Link to the next page of activities.
@property (copy) NSString *nextLink;
// The continuation token, which is used to page through large result sets.
// Provide this value in a subsequent request to return the next page of
// results.
@property (copy) NSString *nextPageToken;
// Link to this activity resource.
@property (copy) NSString *selfLink;
// The title of this collection of activities.
@property (copy) NSString *title;
// The time at which this collection of activities was last updated. Formatted
// as an RFC 3339 timestamp.
@property (retain) GTLDateTime *updated;
@end

View File

@@ -0,0 +1,64 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusActivityFeed.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusActivityFeed (0 custom class methods, 9 custom properties)
#import "GTLPlusActivityFeed.h"
#import "GTLPlusActivity.h"
// ----------------------------------------------------------------------------
//
// GTLPlusActivityFeed
//
@implementation GTLPlusActivityFeed
@dynamic ETag, identifier, items, kind, nextLink, nextPageToken, selfLink,
title, updated;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"etag", @"ETag",
@"id", @"identifier",
nil];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusActivity class]
forKey:@"items"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#activityFeed"];
}
@end

View File

@@ -0,0 +1,183 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusComment.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusComment (0 custom class methods, 11 custom properties)
// GTLPlusCommentActor (0 custom class methods, 4 custom properties)
// GTLPlusCommentInReplyToItem (0 custom class methods, 2 custom properties)
// GTLPlusCommentObject (0 custom class methods, 3 custom properties)
// GTLPlusCommentPlusoners (0 custom class methods, 1 custom properties)
// GTLPlusCommentActorImage (0 custom class methods, 1 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusCommentActor;
@class GTLPlusCommentActorImage;
@class GTLPlusCommentInReplyToItem;
@class GTLPlusCommentObject;
@class GTLPlusCommentPlusoners;
// ----------------------------------------------------------------------------
//
// GTLPlusComment
//
@interface GTLPlusComment : GTLObject
// The person who posted this comment.
@property (retain) GTLPlusCommentActor *actor;
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The ID of this comment.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The activity this comment replied to.
@property (retain) NSArray *inReplyTo; // of GTLPlusCommentInReplyToItem
// Identifies this resource as a comment. Value: "plus#comment".
@property (copy) NSString *kind;
// The object of this comment.
@property (retain) GTLPlusCommentObject *object;
// People who +1'd this comment.
@property (retain) GTLPlusCommentPlusoners *plusoners;
// The time at which this comment was initially published. Formatted as an RFC
// 3339 timestamp.
@property (retain) GTLDateTime *published;
// Link to this comment resource.
@property (copy) NSString *selfLink;
// The time at which this comment was last updated. Formatted as an RFC 3339
// timestamp.
@property (retain) GTLDateTime *updated;
// This comment's verb, indicating what action was performed. Possible values
// are:
// - "post" - Publish content to the stream.
@property (copy) NSString *verb;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentActor
//
@interface GTLPlusCommentActor : GTLObject
// The name of this actor, suitable for display.
@property (copy) NSString *displayName;
// The ID of the actor.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The image representation of this actor.
@property (retain) GTLPlusCommentActorImage *image;
// A link to the person resource for this actor.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentInReplyToItem
//
@interface GTLPlusCommentInReplyToItem : GTLObject
// The ID of the activity.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The URL of the activity.
@property (copy) NSString *url;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentObject
//
@interface GTLPlusCommentObject : GTLObject
// The HTML-formatted content, suitable for display.
@property (copy) NSString *content;
// The object type of this comment. Possible values are:
// - "comment" - A comment in reply to an activity.
@property (copy) NSString *objectType;
// The content (text) as provided by the author, stored without any HTML
// formatting. When creating or updating a comment, this value must be supplied
// as plain text in the request.
@property (copy) NSString *originalContent;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentPlusoners
//
@interface GTLPlusCommentPlusoners : GTLObject
// Total number of people who +1'd this comment.
@property (retain) NSNumber *totalItems; // unsignedIntValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentActorImage
//
@interface GTLPlusCommentActorImage : GTLObject
// The URL of the actor's profile photo. To re-size the image and crop it to a
// square, append the query string ?sz=x, where x is the dimension in pixels of
// each side.
@property (copy) NSString *url;
@end

View File

@@ -0,0 +1,133 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusComment.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusComment (0 custom class methods, 11 custom properties)
// GTLPlusCommentActor (0 custom class methods, 4 custom properties)
// GTLPlusCommentInReplyToItem (0 custom class methods, 2 custom properties)
// GTLPlusCommentObject (0 custom class methods, 3 custom properties)
// GTLPlusCommentPlusoners (0 custom class methods, 1 custom properties)
// GTLPlusCommentActorImage (0 custom class methods, 1 custom properties)
#import "GTLPlusComment.h"
// ----------------------------------------------------------------------------
//
// GTLPlusComment
//
@implementation GTLPlusComment
@dynamic actor, ETag, identifier, inReplyTo, kind, object, plusoners, published,
selfLink, updated, verb;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"etag", @"ETag",
@"id", @"identifier",
nil];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusCommentInReplyToItem class]
forKey:@"inReplyTo"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#comment"];
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentActor
//
@implementation GTLPlusCommentActor
@dynamic displayName, identifier, image, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentInReplyToItem
//
@implementation GTLPlusCommentInReplyToItem
@dynamic identifier, url;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentObject
//
@implementation GTLPlusCommentObject
@dynamic content, objectType, originalContent;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentPlusoners
//
@implementation GTLPlusCommentPlusoners
@dynamic totalItems;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusCommentActorImage
//
@implementation GTLPlusCommentActorImage
@dynamic url;
@end

View File

@@ -0,0 +1,78 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusCommentFeed.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusCommentFeed (0 custom class methods, 8 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusComment;
// ----------------------------------------------------------------------------
//
// GTLPlusCommentFeed
//
// This class supports NSFastEnumeration over its "items" property. It also
// supports -itemAtIndex: to retrieve individual objects from "items".
@interface GTLPlusCommentFeed : GTLCollectionObject
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The ID of this collection of comments.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// The comments in this page of results.
@property (retain) NSArray *items; // of GTLPlusComment
// Identifies this resource as a collection of comments. Value:
// "plus#commentFeed".
@property (copy) NSString *kind;
// Link to the next page of activities.
@property (copy) NSString *nextLink;
// The continuation token, which is used to page through large result sets.
// Provide this value in a subsequent request to return the next page of
// results.
@property (copy) NSString *nextPageToken;
// The title of this collection of comments.
@property (copy) NSString *title;
// The time at which this collection of comments was last updated. Formatted as
// an RFC 3339 timestamp.
@property (retain) GTLDateTime *updated;
@end

View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusCommentFeed.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusCommentFeed (0 custom class methods, 8 custom properties)
#import "GTLPlusCommentFeed.h"
#import "GTLPlusComment.h"
// ----------------------------------------------------------------------------
//
// GTLPlusCommentFeed
//
@implementation GTLPlusCommentFeed
@dynamic ETag, identifier, items, kind, nextLink, nextPageToken, title, updated;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys:
@"etag", @"ETag",
@"id", @"identifier",
nil];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusComment class]
forKey:@"items"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#commentFeed"];
}
@end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -35,12 +35,23 @@
#endif #endif
// Authorization scope // Authorization scope
// Know your name, basic info, and list of people you're connected to on Google+
GTL_EXTERN NSString * const kGTLAuthScopePlusLogin; // "https://www.googleapis.com/auth/plus.login"
// Know who you are on Google // Know who you are on Google
GTL_EXTERN NSString * const kGTLAuthScopePlusMe; // "https://www.googleapis.com/auth/plus.me" GTL_EXTERN NSString * const kGTLAuthScopePlusMe; // "https://www.googleapis.com/auth/plus.me"
// View and manage user activity information in Google+
GTL_EXTERN NSString * const kGTLAuthScopePlusMomentsWrite; // "https://www.googleapis.com/auth/plus.moments.write"
// View your email address
GTL_EXTERN NSString * const kGTLAuthScopePlusUserinfoEmail; // "https://www.googleapis.com/auth/userinfo.email"
// Collection // Collection
GTL_EXTERN NSString * const kGTLPlusCollectionVault; // "vault" GTL_EXTERN NSString * const kGTLPlusCollectionPlusoners; // "plusoners"
GTL_EXTERN NSString * const kGTLPlusCollectionPublic; // "public"
GTL_EXTERN NSString * const kGTLPlusCollectionResharers; // "resharers"
GTL_EXTERN NSString * const kGTLPlusCollectionVault; // "vault"
GTL_EXTERN NSString * const kGTLPlusCollectionVisible; // "visible"
// OrderBy
GTL_EXTERN NSString * const kGTLPlusOrderByAlphabetical; // "alphabetical"
GTL_EXTERN NSString * const kGTLPlusOrderByBest; // "best"
GTL_EXTERN NSString * const kGTLPlusOrderByRecent; // "recent"
// SortOrder
GTL_EXTERN NSString * const kGTLPlusSortOrderAscending; // "ascending"
GTL_EXTERN NSString * const kGTLPlusSortOrderDescending; // "descending"

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,18 +20,30 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
#import "GTLPlusConstants.h" #import "GTLPlusConstants.h"
// Authorization scope // Authorization scope
NSString * const kGTLAuthScopePlusMe = @"https://www.googleapis.com/auth/plus.me"; NSString * const kGTLAuthScopePlusLogin = @"https://www.googleapis.com/auth/plus.login";
NSString * const kGTLAuthScopePlusMomentsWrite = @"https://www.googleapis.com/auth/plus.moments.write"; NSString * const kGTLAuthScopePlusMe = @"https://www.googleapis.com/auth/plus.me";
NSString * const kGTLAuthScopePlusUserinfoEmail = @"https://www.googleapis.com/auth/userinfo.email";
// Collection // Collection
NSString * const kGTLPlusCollectionVault = @"vault"; NSString * const kGTLPlusCollectionPlusoners = @"plusoners";
NSString * const kGTLPlusCollectionPublic = @"public";
NSString * const kGTLPlusCollectionResharers = @"resharers";
NSString * const kGTLPlusCollectionVault = @"vault";
NSString * const kGTLPlusCollectionVisible = @"visible";
// OrderBy
NSString * const kGTLPlusOrderByAlphabetical = @"alphabetical";
NSString * const kGTLPlusOrderByBest = @"best";
NSString * const kGTLPlusOrderByRecent = @"recent";
// SortOrder
NSString * const kGTLPlusSortOrderAscending = @"ascending";
NSString * const kGTLPlusSortOrderDescending = @"descending";

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusItemScope (0 custom class methods, 55 custom properties) // GTLPlusItemScope (0 custom class methods, 55 custom properties)
@@ -169,11 +169,11 @@
// belongs to. // belongs to.
@property (retain) GTLPlusItemScope *partOfTVSeries; @property (retain) GTLPlusItemScope *partOfTVSeries;
// The main performer or performers of the eventfor example, a presenter, // The main performer or performers of the event-for example, a presenter,
// musician, or actor. // musician, or actor.
@property (retain) NSArray *performers; // of GTLPlusItemScope @property (retain) NSArray *performers; // of GTLPlusItemScope
// Player type requiredfor example, Flash or Silverlight. // Player type required-for example, Flash or Silverlight.
@property (copy) NSString *playerType; @property (copy) NSString *playerType;
// Postal code. // Postal code.
@@ -186,7 +186,7 @@
@property (copy) NSString *ratingValue; @property (copy) NSString *ratingValue;
// Review rating. // Review rating.
@property (retain) NSArray *reviewRating; // of GTLPlusItemScope @property (retain) GTLPlusItemScope *reviewRating;
// The start date and time of the event (in ISO 8601 date format). // The start date and time of the event (in ISO 8601 date format).
@property (copy) NSString *startDate; @property (copy) NSString *startDate;
@@ -213,7 +213,7 @@
// The item type. // The item type.
@property (copy) NSString *type; @property (copy) NSString *type;
// A url for this scope. // A URL for the item upon which the action was performed.
@property (copy) NSString *url; @property (copy) NSString *url;
// The width of the media object. // The width of the media object.

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusItemScope (0 custom class methods, 55 custom properties) // GTLPlusItemScope (0 custom class methods, 55 custom properties)
@@ -66,7 +66,6 @@
[GTLPlusItemScope class], @"author", [GTLPlusItemScope class], @"author",
[GTLPlusItemScope class], @"contributor", [GTLPlusItemScope class], @"contributor",
[GTLPlusItemScope class], @"performers", [GTLPlusItemScope class], @"performers",
[GTLPlusItemScope class], @"reviewRating",
nil]; nil];
return map; return map;
} }

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,14 +20,13 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusMoment (0 custom class methods, 6 custom properties) // GTLPlusMoment (0 custom class methods, 6 custom properties)
// GTLPlusMomentVerb (0 custom class methods, 1 custom properties)
#if GTL_BUILT_AS_FRAMEWORK #if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h" #import "GTL/GTLObject.h"
@@ -36,7 +35,6 @@
#endif #endif
@class GTLPlusItemScope; @class GTLPlusItemScope;
@class GTLPlusMomentVerb;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// //
@@ -45,35 +43,23 @@
@interface GTLPlusMoment : GTLObject @interface GTLPlusMoment : GTLObject
// The moment ID.
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
// Identifies this resource as a moment. // Identifies this resource as a moment.
@property (copy) NSString *kind; @property (copy) NSString *kind;
// The object generated by performing the action on the item // The object generated by performing the action on the item
@property (retain) GTLPlusItemScope *result; @property (retain) GTLPlusItemScope *result;
// Timestamp of the action (when it occured) in RFC3339 format. // Time stamp of when the action occurred in RFC3339 format.
@property (retain) GTLDateTime *startDate; @property (retain) GTLDateTime *startDate;
// The object on which the action was performed // The object on which the action was performed.
@property (retain) GTLPlusItemScope *target; @property (retain) GTLPlusItemScope *target;
// The schema.org activity type // The schema.org activity type.
@property (copy) NSString *type; @property (copy) NSString *type;
// The action the user performed
@property (retain) GTLPlusMomentVerb *verb;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusMomentVerb
//
@interface GTLPlusMomentVerb : GTLObject
// Url name of the verb
@property (copy) NSString *url;
@end @end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,14 +20,13 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusMoment (0 custom class methods, 6 custom properties) // GTLPlusMoment (0 custom class methods, 6 custom properties)
// GTLPlusMomentVerb (0 custom class methods, 1 custom properties)
#import "GTLPlusMoment.h" #import "GTLPlusMoment.h"
@@ -39,20 +38,17 @@
// //
@implementation GTLPlusMoment @implementation GTLPlusMoment
@dynamic kind, result, startDate, target, type, verb; @dynamic identifier, kind, result, startDate, target, type;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
+ (void)load { + (void)load {
[self registerObjectClassForKind:@"plus#moment"]; [self registerObjectClassForKind:@"plus#moment"];
} }
@end @end
// ----------------------------------------------------------------------------
//
// GTLPlusMomentVerb
//
@implementation GTLPlusMomentVerb
@dynamic url;
@end

View File

@@ -0,0 +1,76 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusMomentsFeed.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusMomentsFeed (0 custom class methods, 8 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusMoment;
// ----------------------------------------------------------------------------
//
// GTLPlusMomentsFeed
//
// This class supports NSFastEnumeration over its "items" property. It also
// supports -itemAtIndex: to retrieve individual objects from "items".
@interface GTLPlusMomentsFeed : GTLCollectionObject
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The moments in this page of results.
@property (retain) NSArray *items; // of GTLPlusMoment
// Identifies this resource as a collection of moments. Value:
// "plus#momentsFeed".
@property (copy) NSString *kind;
// Link to the next page of moments.
@property (copy) NSString *nextLink;
// The continuation token, which is used to page through large result sets.
// Provide this value in a subsequent request to return the next page of
// results.
@property (copy) NSString *nextPageToken;
// Link to this page of moments.
@property (copy) NSString *selfLink;
// The title of this collection of moments.
@property (copy) NSString *title;
// The RFC 339 timestamp for when this collection of moments was last updated.
@property (retain) GTLDateTime *updated;
@end

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusMomentsFeed.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusMomentsFeed (0 custom class methods, 8 custom properties)
#import "GTLPlusMomentsFeed.h"
#import "GTLPlusMoment.h"
// ----------------------------------------------------------------------------
//
// GTLPlusMomentsFeed
//
@implementation GTLPlusMomentsFeed
@dynamic ETag, items, kind, nextLink, nextPageToken, selfLink, title, updated;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"etag"
forKey:@"ETag"];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusMoment class]
forKey:@"items"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#momentsFeed"];
}
@end

View File

@@ -0,0 +1,76 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusPeopleFeed.h
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusPeopleFeed (0 custom class methods, 7 custom properties)
#if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h"
#else
#import "GTLObject.h"
#endif
@class GTLPlusPerson;
// ----------------------------------------------------------------------------
//
// GTLPlusPeopleFeed
//
// This class supports NSFastEnumeration over its "items" property. It also
// supports -itemAtIndex: to retrieve individual objects from "items".
@interface GTLPlusPeopleFeed : GTLCollectionObject
// ETag of this response for caching purposes.
@property (copy) NSString *ETag;
// The people in this page of results. Each item includes the id, displayName,
// image, and url for the person. To retrieve additional profile data, see the
// people.get method.
@property (retain) NSArray *items; // of GTLPlusPerson
// Identifies this resource as a collection of people. Value: "plus#peopleFeed".
@property (copy) NSString *kind;
// The continuation token, which is used to page through large result sets.
// Provide this value in a subsequent request to return the next page of
// results.
@property (copy) NSString *nextPageToken;
// Link to this resource.
@property (copy) NSString *selfLink;
// The title of this collection of people.
@property (copy) NSString *title;
// The total number of people available in this list. The number of people in a
// response might be smaller due to paging. This might not be set for all
// collections.
@property (retain) NSNumber *totalItems; // intValue
@end

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2013 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.
*/
//
// GTLPlusPeopleFeed.m
//
// ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service.
// Service:
// Google+ API (plus/v1)
// Description:
// The Google+ API enables developers to build on top of the Google+ platform.
// Documentation:
// https://developers.google.com/+/api/
// Classes:
// GTLPlusPeopleFeed (0 custom class methods, 7 custom properties)
#import "GTLPlusPeopleFeed.h"
#import "GTLPlusPerson.h"
// ----------------------------------------------------------------------------
//
// GTLPlusPeopleFeed
//
@implementation GTLPlusPeopleFeed
@dynamic ETag, items, kind, nextPageToken, selfLink, title, totalItems;
+ (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"etag"
forKey:@"ETag"];
return map;
}
+ (NSDictionary *)arrayPropertyToClassMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:[GTLPlusPerson class]
forKey:@"items"];
return map;
}
+ (void)load {
[self registerObjectClassForKind:@"plus#peopleFeed"];
}
@end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,19 +20,23 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusPerson (0 custom class methods, 21 custom properties) // GTLPlusPerson (0 custom class methods, 28 custom properties)
// GTLPlusPersonAgeRange (0 custom class methods, 2 custom properties)
// GTLPlusPersonCover (0 custom class methods, 3 custom properties)
// GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties) // GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonImage (0 custom class methods, 1 custom properties) // GTLPlusPersonImage (0 custom class methods, 1 custom properties)
// GTLPlusPersonName (0 custom class methods, 6 custom properties) // GTLPlusPersonName (0 custom class methods, 6 custom properties)
// GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties) // GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties)
// GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties) // GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties)
// GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties) // GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonCoverCoverInfo (0 custom class methods, 2 custom properties)
// GTLPlusPersonCoverCoverPhoto (0 custom class methods, 3 custom properties)
#if GTL_BUILT_AS_FRAMEWORK #if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLObject.h" #import "GTL/GTLObject.h"
@@ -40,6 +44,10 @@
#import "GTLObject.h" #import "GTLObject.h"
#endif #endif
@class GTLPlusPersonAgeRange;
@class GTLPlusPersonCover;
@class GTLPlusPersonCoverCoverInfo;
@class GTLPlusPersonCoverCoverPhoto;
@class GTLPlusPersonEmailsItem; @class GTLPlusPersonEmailsItem;
@class GTLPlusPersonImage; @class GTLPlusPersonImage;
@class GTLPlusPersonName; @class GTLPlusPersonName;
@@ -57,9 +65,22 @@
// A short biography for this person. // A short biography for this person.
@property (copy) NSString *aboutMe; @property (copy) NSString *aboutMe;
// The age range of the person.
@property (retain) GTLPlusPersonAgeRange *ageRange;
// The person's date of birth, represented as YYYY-MM-DD. // The person's date of birth, represented as YYYY-MM-DD.
@property (copy) NSString *birthday; @property (copy) NSString *birthday;
// The "bragging rights" line of this person.
@property (copy) NSString *braggingRights;
// If a Google+ Page and for followers who are visible, the number of people who
// have added this page to a circle.
@property (retain) NSNumber *circledByCount; // intValue
// The cover photo content.
@property (retain) GTLPlusPersonCover *cover;
// The current location for this person. // The current location for this person.
@property (copy) NSString *currentLocation; @property (copy) NSString *currentLocation;
@@ -91,11 +112,14 @@
// The representation of the person's profile photo. // The representation of the person's profile photo.
@property (retain) GTLPlusPersonImage *image; @property (retain) GTLPlusPersonImage *image;
// Whether this user has signed up for Google+.
@property (retain) NSNumber *isPlusUser; // boolValue
// Identifies this resource as a person. Value: "plus#person". // Identifies this resource as a person. Value: "plus#person".
@property (copy) NSString *kind; @property (copy) NSString *kind;
// The languages spoken by this person. // The user's preferred language for rendering.
@property (retain) NSArray *languagesSpoken; // of NSString @property (copy) NSString *language;
// An object representation of the individual components of a person's name. // An object representation of the individual components of a person's name.
@property (retain) GTLPlusPersonName *name; @property (retain) GTLPlusPersonName *name;
@@ -114,6 +138,9 @@
// A list of places where this person has lived. // A list of places where this person has lived.
@property (retain) NSArray *placesLived; // of GTLPlusPersonPlacesLivedItem @property (retain) NSArray *placesLived; // of GTLPlusPersonPlacesLivedItem
// If a Google+ Page, the number of people who have +1'ed this page.
@property (retain) NSNumber *plusOneCount; // intValue
// The person's relationship status. Possible values are: // The person's relationship status. Possible values are:
// - "single" - Person is single. // - "single" - Person is single.
// - "in_a_relationship" - Person is in a relationship. // - "in_a_relationship" - Person is in a relationship.
@@ -135,6 +162,45 @@
// A list of URLs for this person. // A list of URLs for this person.
@property (retain) NSArray *urls; // of GTLPlusPersonUrlsItem @property (retain) NSArray *urls; // of GTLPlusPersonUrlsItem
// Whether the person or Google+ Page has been verified.
@property (retain) NSNumber *verified; // boolValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonAgeRange
//
@interface GTLPlusPersonAgeRange : GTLObject
// The age range's upper bound, if any.
@property (retain) NSNumber *max; // intValue
// The age range's lower bound, if any.
@property (retain) NSNumber *min; // intValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCover
//
@interface GTLPlusPersonCover : GTLObject
// Extra information about the cover photo.
@property (retain) GTLPlusPersonCoverCoverInfo *coverInfo;
// The person's primary cover image.
@property (retain) GTLPlusPersonCoverCoverPhoto *coverPhoto;
// The layout of the cover art. Possible values are:
// - "banner" - One large image banner.
@property (copy) NSString *layout;
@end @end
@@ -210,17 +276,17 @@
@interface GTLPlusPersonOrganizationsItem : GTLObject @interface GTLPlusPersonOrganizationsItem : GTLObject
// The department within the organization. // The department within the organization. Deprecated.
@property (copy) NSString *department; @property (copy) NSString *department;
// A short description of the person's role in this organization. // A short description of the person's role in this organization. Deprecated.
// Remapped to 'descriptionProperty' to avoid NSObject's 'description'. // Remapped to 'descriptionProperty' to avoid NSObject's 'description'.
@property (copy) NSString *descriptionProperty; @property (copy) NSString *descriptionProperty;
// The date the person left this organization. // The date the person left this organization.
@property (copy) NSString *endDate; @property (copy) NSString *endDate;
// The location of this organization. // The location of this organization. Deprecated.
@property (copy) NSString *location; @property (copy) NSString *location;
// The name of the organization. // The name of the organization.
@@ -283,3 +349,40 @@
@property (copy) NSString *value; @property (copy) NSString *value;
@end @end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCoverCoverInfo
//
@interface GTLPlusPersonCoverCoverInfo : GTLObject
// The difference between the left position of the image cover and the actual
// displayed cover image. Only valid for BANNER layout.
@property (retain) NSNumber *leftImageOffset; // intValue
// The difference between the top position of the image cover and the actual
// displayed cover image. Only valid for BANNER layout.
@property (retain) NSNumber *topImageOffset; // intValue
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCoverCoverPhoto
//
@interface GTLPlusPersonCoverCoverPhoto : GTLObject
// The height to the image.
@property (retain) NSNumber *height; // intValue
// The url to the image.
@property (copy) NSString *url;
// The width to the image.
@property (retain) NSNumber *width; // intValue
@end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,19 +20,23 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLPlusPerson (0 custom class methods, 21 custom properties) // GTLPlusPerson (0 custom class methods, 28 custom properties)
// GTLPlusPersonAgeRange (0 custom class methods, 2 custom properties)
// GTLPlusPersonCover (0 custom class methods, 3 custom properties)
// GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties) // GTLPlusPersonEmailsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonImage (0 custom class methods, 1 custom properties) // GTLPlusPersonImage (0 custom class methods, 1 custom properties)
// GTLPlusPersonName (0 custom class methods, 6 custom properties) // GTLPlusPersonName (0 custom class methods, 6 custom properties)
// GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties) // GTLPlusPersonOrganizationsItem (0 custom class methods, 9 custom properties)
// GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties) // GTLPlusPersonPlacesLivedItem (0 custom class methods, 2 custom properties)
// GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties) // GTLPlusPersonUrlsItem (0 custom class methods, 3 custom properties)
// GTLPlusPersonCoverCoverInfo (0 custom class methods, 2 custom properties)
// GTLPlusPersonCoverCoverPhoto (0 custom class methods, 3 custom properties)
#import "GTLPlusPerson.h" #import "GTLPlusPerson.h"
@@ -42,10 +46,11 @@
// //
@implementation GTLPlusPerson @implementation GTLPlusPerson
@dynamic aboutMe, birthday, currentLocation, displayName, emails, ETag, gender, @dynamic aboutMe, ageRange, birthday, braggingRights, circledByCount, cover,
hasApp, identifier, image, kind, languagesSpoken, name, nickname, currentLocation, displayName, emails, ETag, gender, hasApp, identifier,
objectType, organizations, placesLived, relationshipStatus, tagline, image, isPlusUser, kind, language, name, nickname, objectType,
url, urls; organizations, placesLived, plusOneCount, relationshipStatus, tagline,
url, urls, verified;
+ (NSDictionary *)propertyToJSONKeyMap { + (NSDictionary *)propertyToJSONKeyMap {
NSDictionary *map = NSDictionary *map =
@@ -60,7 +65,6 @@
NSDictionary *map = NSDictionary *map =
[NSDictionary dictionaryWithObjectsAndKeys: [NSDictionary dictionaryWithObjectsAndKeys:
[GTLPlusPersonEmailsItem class], @"emails", [GTLPlusPersonEmailsItem class], @"emails",
[NSString class], @"languagesSpoken",
[GTLPlusPersonOrganizationsItem class], @"organizations", [GTLPlusPersonOrganizationsItem class], @"organizations",
[GTLPlusPersonPlacesLivedItem class], @"placesLived", [GTLPlusPersonPlacesLivedItem class], @"placesLived",
[GTLPlusPersonUrlsItem class], @"urls", [GTLPlusPersonUrlsItem class], @"urls",
@@ -75,6 +79,26 @@
@end @end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonAgeRange
//
@implementation GTLPlusPersonAgeRange
@dynamic max, min;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCover
//
@implementation GTLPlusPersonCover
@dynamic coverInfo, coverPhoto, layout;
@end
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// //
// GTLPlusPersonEmailsItem // GTLPlusPersonEmailsItem
@@ -143,3 +167,23 @@
@implementation GTLPlusPersonUrlsItem @implementation GTLPlusPersonUrlsItem
@dynamic primary, type, value; @dynamic primary, type, value;
@end @end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCoverCoverInfo
//
@implementation GTLPlusPersonCoverCoverInfo
@dynamic leftImageOffset, topImageOffset;
@end
// ----------------------------------------------------------------------------
//
// GTLPlusPersonCoverCoverPhoto
//
@implementation GTLPlusPersonCoverCoverPhoto
@dynamic height, url, width;
@end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,13 +20,13 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLQueryPlus (2 custom class methods, 4 custom properties) // GTLQueryPlus (12 custom class methods, 15 custom properties)
#if GTL_BUILT_AS_FRAMEWORK #if GTL_BUILT_AS_FRAMEWORK
#import "GTL/GTLQuery.h" #import "GTL/GTLQuery.h"
@@ -48,43 +48,250 @@
// //
// Method-specific parameters; see the comments below for more information. // Method-specific parameters; see the comments below for more information.
// //
@property (copy) NSString *activityId;
@property (copy) NSString *collection; @property (copy) NSString *collection;
@property (copy) NSString *commentId;
@property (assign) BOOL debug; @property (assign) BOOL debug;
// identifier property maps to 'id' in JSON (to avoid Objective C's 'id').
@property (copy) NSString *identifier;
@property (copy) NSString *language;
@property (assign) NSUInteger maxResults;
@property (copy) NSString *orderBy;
@property (copy) NSString *pageToken;
@property (copy) NSString *query;
@property (copy) NSString *sortOrder;
@property (copy) NSString *targetUrl;
@property (copy) NSString *type;
@property (copy) NSString *userId; @property (copy) NSString *userId;
#pragma mark -
#pragma mark "activities" methods
// These create a GTLQueryPlus object.
// Method: plus.activities.get
// Get an activity.
// Required:
// activityId: The ID of the activity to get.
// Authorization scope(s):
// kGTLAuthScopePlusLogin
// kGTLAuthScopePlusMe
// Fetches a GTLPlusActivity.
+ (id)queryForActivitiesGetWithActivityId:(NSString *)activityId;
// Method: plus.activities.list
// List all of the activities in the specified collection for a particular user.
// Required:
// userId: The ID of the user to get activities for. The special value "me"
// can be used to indicate the authenticated user.
// collection: The collection of activities to list.
// kGTLPlusCollectionPublic: All public activities created by the specified
// user.
// Optional:
// maxResults: The maximum number of activities to include in the response,
// which is used for paging. For any response, the actual number returned
// might be less than the specified maxResults. (1..100, default 20)
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response.
// Authorization scope(s):
// kGTLAuthScopePlusLogin
// kGTLAuthScopePlusMe
// Fetches a GTLPlusActivityFeed.
+ (id)queryForActivitiesListWithUserId:(NSString *)userId
collection:(NSString *)collection;
// Method: plus.activities.search
// Search public activities.
// Required:
// query: Full-text search query string.
// Optional:
// language: Specify the preferred language to search with. See search
// language codes for available values. (Default en-US)
// maxResults: The maximum number of activities to include in the response,
// which is used for paging. For any response, the actual number returned
// might be less than the specified maxResults. (1..20, default 10)
// orderBy: Specifies how to order search results. (Default
// kGTLPlusOrderByRecent)
// kGTLPlusOrderByBest: Sort activities by relevance to the user, most
// relevant first.
// kGTLPlusOrderByRecent: Sort activities by published date, most recent
// first.
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response. This token can be of
// any length.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// Fetches a GTLPlusActivityFeed.
+ (id)queryForActivitiesSearchWithQuery:(NSString *)query;
#pragma mark -
#pragma mark "comments" methods
// These create a GTLQueryPlus object.
// Method: plus.comments.get
// Get a comment.
// Required:
// commentId: The ID of the comment to get.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// Fetches a GTLPlusComment.
+ (id)queryForCommentsGetWithCommentId:(NSString *)commentId;
// Method: plus.comments.list
// List all of the comments for an activity.
// Required:
// activityId: The ID of the activity to get comments for.
// Optional:
// maxResults: The maximum number of comments to include in the response,
// which is used for paging. For any response, the actual number returned
// might be less than the specified maxResults. (0..500, default 20)
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response.
// sortOrder: The order in which to sort the list of comments. (Default
// kGTLPlusSortOrderAscending)
// kGTLPlusSortOrderAscending: Sort oldest comments first.
// kGTLPlusSortOrderDescending: Sort newest comments first.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// Fetches a GTLPlusCommentFeed.
+ (id)queryForCommentsListWithActivityId:(NSString *)activityId;
#pragma mark - #pragma mark -
#pragma mark "moments" methods #pragma mark "moments" methods
// These create a GTLQueryPlus object. // These create a GTLQueryPlus object.
// Method: plus.moments.insert // Method: plus.moments.insert
// Record a user activity (e.g Bill watched a video on Youtube) // Record a moment representing a user's activity such as making a purchase or
// commenting on a blog.
// Required: // Required:
// userId: The ID of the user to get activities for. The special value "me" // userId: The ID of the user to record activities for. The only valid values
// can be used to indicate the authenticated user. // are "me" and the ID of the authenticated user.
// collection: The collection to which to write moments. // collection: The collection to which to write moments.
// kGTLPlusCollectionVault: The default collection for writing new moments. // kGTLPlusCollectionVault: The default collection for writing new moments.
// Optional: // Optional:
// debug: Return the moment as written. Should be used only for debugging. // debug: Return the moment as written. Should be used only for debugging.
// Authorization scope(s): // Authorization scope(s):
// kGTLAuthScopePlusMomentsWrite // kGTLAuthScopePlusLogin
// Fetches a GTLPlusMoment. // Fetches a GTLPlusMoment.
+ (id)queryForMomentsInsertWithObject:(GTLPlusMoment *)object + (id)queryForMomentsInsertWithObject:(GTLPlusMoment *)object
userId:(NSString *)userId userId:(NSString *)userId
collection:(NSString *)collection; collection:(NSString *)collection;
// Method: plus.moments.list
// List all of the moments for a particular user.
// Required:
// userId: The ID of the user to get moments for. The special value "me" can
// be used to indicate the authenticated user.
// collection: The collection of moments to list.
// kGTLPlusCollectionVault: All moments created by the requesting
// application for the authenticated user.
// Optional:
// maxResults: The maximum number of moments to include in the response, which
// is used for paging. For any response, the actual number returned might be
// less than the specified maxResults. (1..100, default 20)
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response.
// targetUrl: Only moments containing this targetUrl will be returned.
// type: Only moments of this type will be returned.
// Authorization scope(s):
// kGTLAuthScopePlusLogin
// Fetches a GTLPlusMomentsFeed.
+ (id)queryForMomentsListWithUserId:(NSString *)userId
collection:(NSString *)collection;
// Method: plus.moments.remove
// Delete a moment.
// Required:
// identifier: The ID of the moment to delete.
// Authorization scope(s):
// kGTLAuthScopePlusLogin
+ (id)queryForMomentsRemoveWithIdentifier:(NSString *)identifier;
#pragma mark - #pragma mark -
#pragma mark "people" methods #pragma mark "people" methods
// These create a GTLQueryPlus object. // These create a GTLQueryPlus object.
// Method: plus.people.get // Method: plus.people.get
// Get a person's profile. // Get a person's profile. If your app uses scope
// https://www.googleapis.com/auth/plus.login, this method is guaranteed to
// return ageRange and language.
// Required: // Required:
// userId: The ID of the person to get the profile for. The special value "me" // userId: The ID of the person to get the profile for. The special value "me"
// can be used to indicate the authenticated user. // can be used to indicate the authenticated user.
// Authorization scope(s): // Authorization scope(s):
// kGTLAuthScopePlusLogin
// kGTLAuthScopePlusMe // kGTLAuthScopePlusMe
// kGTLAuthScopePlusUserinfoEmail
// Fetches a GTLPlusPerson. // Fetches a GTLPlusPerson.
+ (id)queryForPeopleGetWithUserId:(NSString *)userId; + (id)queryForPeopleGetWithUserId:(NSString *)userId;
// Method: plus.people.list
// List all of the people in the specified collection.
// Required:
// userId: Get the collection of people for the person identified by the ID or
// use "me" to indiciated the authenticated user.
// collection: The collection of people to list.
// kGTLPlusCollectionVisible: The list of people who this user has added to
// one or more circles, limited to the circles visible to the requesting
// application.
// Optional:
// maxResults: The maximum number of people to include in the response, which
// is used for paging. For any response, the actual number returned might be
// less than the specified maxResults. (1..100, default 100)
// orderBy: The order to return people in.
// kGTLPlusOrderByAlphabetical: Order the people by their display name.
// kGTLPlusOrderByBest: Order people based on the relevence to the viewer.
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response.
// Authorization scope(s):
// kGTLAuthScopePlusLogin
// Fetches a GTLPlusPeopleFeed.
+ (id)queryForPeopleListWithUserId:(NSString *)userId
collection:(NSString *)collection;
// Method: plus.people.listByActivity
// List all of the people in the specified collection for a particular activity.
// Required:
// activityId: The ID of the activity to get the list of people for.
// collection: The collection of people to list.
// kGTLPlusCollectionPlusoners: List all people who have +1'd this
// activity.
// kGTLPlusCollectionResharers: List all people who have reshared this
// activity.
// Optional:
// maxResults: The maximum number of people to include in the response, which
// is used for paging. For any response, the actual number returned might be
// less than the specified maxResults. (1..100, default 20)
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// Fetches a GTLPlusPeopleFeed.
+ (id)queryForPeopleListByActivityWithActivityId:(NSString *)activityId
collection:(NSString *)collection;
// Method: plus.people.search
// Search all public profiles.
// Required:
// query: Specify a query string for full text search of public text in all
// profiles.
// Optional:
// language: Specify the preferred language to search with. See search
// language codes for available values. (Default en-US)
// maxResults: The maximum number of people to include in the response, which
// is used for paging. For any response, the actual number returned might be
// less than the specified maxResults. (1..20, default 10)
// pageToken: The continuation token, which is used to page through large
// result sets. To get the next page of results, set this parameter to the
// value of "nextPageToken" from the previous response. This token can be of
// any length.
// Authorization scope(s):
// kGTLAuthScopePlusMe
// Fetches a GTLPlusPeopleFeed.
+ (id)queryForPeopleSearchWithQuery:(NSString *)query;
@end @end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,22 +20,87 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLQueryPlus (2 custom class methods, 4 custom properties) // GTLQueryPlus (12 custom class methods, 15 custom properties)
#import "GTLQueryPlus.h" #import "GTLQueryPlus.h"
#import "GTLPlusActivity.h"
#import "GTLPlusActivityFeed.h"
#import "GTLPlusComment.h"
#import "GTLPlusCommentFeed.h"
#import "GTLPlusMoment.h" #import "GTLPlusMoment.h"
#import "GTLPlusMomentsFeed.h"
#import "GTLPlusPeopleFeed.h"
#import "GTLPlusPerson.h" #import "GTLPlusPerson.h"
@implementation GTLQueryPlus @implementation GTLQueryPlus
@dynamic collection, debug, fields, userId; @dynamic activityId, collection, commentId, debug, fields, identifier, language,
maxResults, orderBy, pageToken, query, sortOrder, targetUrl, type,
userId;
+ (NSDictionary *)parameterNameMap {
NSDictionary *map =
[NSDictionary dictionaryWithObject:@"id"
forKey:@"identifier"];
return map;
}
#pragma mark -
#pragma mark "activities" methods
// These create a GTLQueryPlus object.
+ (id)queryForActivitiesGetWithActivityId:(NSString *)activityId {
NSString *methodName = @"plus.activities.get";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.activityId = activityId;
query.expectedObjectClass = [GTLPlusActivity class];
return query;
}
+ (id)queryForActivitiesListWithUserId:(NSString *)userId
collection:(NSString *)collection {
NSString *methodName = @"plus.activities.list";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.userId = userId;
query.collection = collection;
query.expectedObjectClass = [GTLPlusActivityFeed class];
return query;
}
+ (id)queryForActivitiesSearchWithQuery:(NSString *)query_param {
NSString *methodName = @"plus.activities.search";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.query = query_param;
query.expectedObjectClass = [GTLPlusActivityFeed class];
return query;
}
#pragma mark -
#pragma mark "comments" methods
// These create a GTLQueryPlus object.
+ (id)queryForCommentsGetWithCommentId:(NSString *)commentId {
NSString *methodName = @"plus.comments.get";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.commentId = commentId;
query.expectedObjectClass = [GTLPlusComment class];
return query;
}
+ (id)queryForCommentsListWithActivityId:(NSString *)activityId {
NSString *methodName = @"plus.comments.list";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.activityId = activityId;
query.expectedObjectClass = [GTLPlusCommentFeed class];
return query;
}
#pragma mark - #pragma mark -
#pragma mark "moments" methods #pragma mark "moments" methods
@@ -57,6 +122,23 @@
return query; return query;
} }
+ (id)queryForMomentsListWithUserId:(NSString *)userId
collection:(NSString *)collection {
NSString *methodName = @"plus.moments.list";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.userId = userId;
query.collection = collection;
query.expectedObjectClass = [GTLPlusMomentsFeed class];
return query;
}
+ (id)queryForMomentsRemoveWithIdentifier:(NSString *)identifier {
NSString *methodName = @"plus.moments.remove";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.identifier = identifier;
return query;
}
#pragma mark - #pragma mark -
#pragma mark "people" methods #pragma mark "people" methods
// These create a GTLQueryPlus object. // These create a GTLQueryPlus object.
@@ -69,4 +151,32 @@
return query; return query;
} }
+ (id)queryForPeopleListWithUserId:(NSString *)userId
collection:(NSString *)collection {
NSString *methodName = @"plus.people.list";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.userId = userId;
query.collection = collection;
query.expectedObjectClass = [GTLPlusPeopleFeed class];
return query;
}
+ (id)queryForPeopleListByActivityWithActivityId:(NSString *)activityId
collection:(NSString *)collection {
NSString *methodName = @"plus.people.listByActivity";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.activityId = activityId;
query.collection = collection;
query.expectedObjectClass = [GTLPlusPeopleFeed class];
return query;
}
+ (id)queryForPeopleSearchWithQuery:(NSString *)query_param {
NSString *methodName = @"plus.people.search";
GTLQueryPlus *query = [self queryWithMethodName:methodName];
query.query = query_param;
query.expectedObjectClass = [GTLPlusPeopleFeed class];
return query;
}
@end @end

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLServicePlus (0 custom class methods, 0 custom properties) // GTLServicePlus (0 custom class methods, 0 custom properties)

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2012 Google Inc. /* Copyright (c) 2013 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NOTE: This file is generated from Google APIs Discovery Service. // NOTE: This file is generated from Google APIs Discovery Service.
// Service: // Service:
// Google+ API (plus/v1moments) // Google+ API (plus/v1)
// Description: // Description:
// The Google+ API enables developers to build on top of the Google+ platform. // The Google+ API enables developers to build on top of the Google+ platform.
// Documentation: // Documentation:
// http://developers.google.com/+/api/ // https://developers.google.com/+/api/
// Classes: // Classes:
// GTLServicePlus (0 custom class methods, 0 custom properties) // GTLServicePlus (0 custom class methods, 0 custom properties)
@@ -38,8 +38,16 @@
+ (NSArray *)checkClasses { + (NSArray *)checkClasses {
NSArray *classes = [NSArray arrayWithObjects: NSArray *classes = [NSArray arrayWithObjects:
[GTLQueryPlus class], [GTLQueryPlus class],
[GTLPlusAcl class],
[GTLPlusAclentryResource class],
[GTLPlusActivity class],
[GTLPlusActivityFeed class],
[GTLPlusComment class],
[GTLPlusCommentFeed class],
[GTLPlusItemScope class], [GTLPlusItemScope class],
[GTLPlusMoment class], [GTLPlusMoment class],
[GTLPlusMomentsFeed class],
[GTLPlusPeopleFeed class],
[GTLPlusPerson class], [GTLPlusPerson class],
nil]; nil];
return classes; return classes;
@@ -50,7 +58,7 @@
self = [super init]; self = [super init];
if (self) { if (self) {
// Version from discovery. // Version from discovery.
self.apiVersion = @"v1moments"; self.apiVersion = @"v1";
// From discovery. Where to send JSON-RPC. // From discovery. Where to send JSON-RPC.
// Turn off prettyPrint for this service to save bandwidth (especially on // Turn off prettyPrint for this service to save bandwidth (especially on

View File

@@ -17,6 +17,9 @@
// GTLQuery.h // GTLQuery.h
// //
// Query documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Query_Operations
#import "GTLObject.h" #import "GTLObject.h"
#import "GTLUploadParameters.h" #import "GTLUploadParameters.h"
@@ -113,15 +116,15 @@
#endif #endif
// methodName is the RPC method name to use. // methodName is the RPC method name to use.
+ (id)queryWithMethodName:(NSString *)methodName; + (id)queryWithMethodName:(NSString *)methodName GTL_NONNULL((1));
// methodName is the RPC method name to use. // methodName is the RPC method name to use.
- (id)initWithMethodName:(NSString *)method; - (id)initWithMethodName:(NSString *)method GTL_NONNULL((1));
// If you need to set a parameter that is not listed as a property for a // If you need to set a parameter that is not listed as a property for a
// query class, you can do so via this api. If you need to clear it after // query class, you can do so via this api. If you need to clear it after
// setting, pass nil for obj. // setting, pass nil for obj.
- (void)setCustomParameter:(id)obj forKey:(NSString *)key; - (void)setCustomParameter:(id)obj forKey:(NSString *)key GTL_NONNULL((2));
// Auto-generated request IDs // Auto-generated request IDs
+ (NSString *)nextRequestID; + (NSString *)nextRequestID;

View File

@@ -108,6 +108,12 @@ static NSString *const kJSONKey = @"jsonKey";
canBeCached = NO; canBeCached = NO;
} else if ([obj isKindOfClass:[GTLObject class]]) { } else if ([obj isKindOfClass:[GTLObject class]]) {
result = [obj JSON]; result = [obj JSON];
if (result == nil) {
// adding an empty object; it should have a JSON dictionary so it can
// hold future assignments
[obj setJSON:[NSMutableDictionary dictionary]];
result = [obj JSON];
}
} else if ([obj isKindOfClass:[NSArray class]]) { } else if ([obj isKindOfClass:[NSArray class]]) {
checkExpected = NO; checkExpected = NO;
NSArray *array = obj; NSArray *array = obj;

View File

@@ -17,6 +17,9 @@
// GTLService.h // GTLService.h
// //
// Service object documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Services_and_Tickets
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "GTLDefines.h" #import "GTLDefines.h"
@@ -123,8 +126,8 @@ typedef void *GTLServiceUploadProgressBlock;
NSUInteger uploadChunkSize_; // zero when uploading via multi-part MIME http body NSUInteger uploadChunkSize_; // zero when uploading via multi-part MIME http body
BOOL isRetryEnabled_; // user allows auto-retries BOOL isRetryEnabled_; // user allows auto-retries
SEL retrySelector_; // optional; set with setServiceRetrySelector SEL retrySelector_; // optional; set with setServiceRetrySelector
NSTimeInterval maxRetryInterval_; // default to 600. seconds NSTimeInterval maxRetryInterval_; // default to 600. seconds
BOOL shouldFetchNextPages_; BOOL shouldFetchNextPages_;
@@ -152,15 +155,16 @@ typedef void *GTLServiceUploadProgressBlock;
// be nil.) // be nil.)
// //
// If the query object is a GTLBatchQuery, the object passed to the callback // If the query object is a GTLBatchQuery, the object passed to the callback
// will be a GTLBatchResult // will be a GTLBatchResult; see the batch query documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Batch_Operations
- (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query - (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
#if NS_BLOCKS_AVAILABLE #if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query - (GTLServiceTicket *)executeQuery:(id<GTLQueryProtocol>)query
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
#endif #endif
// Automatic page fetches // Automatic page fetches
@@ -227,85 +231,85 @@ typedef void *GTLServiceUploadProgressBlock;
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
objectClass:(Class)objectClass objectClass:(Class)objectClass
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName - (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
insertingObject:(GTLObject *)bodyObject insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass objectClass:(Class)objectClass
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName - (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
insertingObject:(GTLObject *)bodyObject insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass objectClass:(Class)objectClass
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
#if NS_BLOCKS_AVAILABLE #if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName - (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
objectClass:(Class)objectClass objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName - (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
insertingObject:(GTLObject *)bodyObject insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName - (GTLServiceTicket *)fetchObjectWithMethodNamed:(NSString *)methodName
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
insertingObject:(GTLObject *)bodyObject insertingObject:(GTLObject *)bodyObject
objectClass:(Class)objectClass objectClass:(Class)objectClass
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
#endif #endif
#pragma mark REST Fetch Methods #pragma mark REST Fetch Methods
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL - (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL - (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
objectClass:(Class)objectClass objectClass:(Class)objectClass
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
- (GTLServiceTicket *)fetchPublicObjectWithURL:(NSURL *)objectURL - (GTLServiceTicket *)fetchPublicObjectWithURL:(NSURL *)objectURL
objectClass:(Class)objectClass objectClass:(Class)objectClass
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut - (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL forURL:(NSURL *)destinationURL
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1,2));
- (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut - (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL forURL:(NSURL *)destinationURL
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1,2));
- (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL - (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL
ETag:(NSString *)etagOrNil ETag:(NSString *)etagOrNil
delegate:(id)delegate delegate:(id)delegate
didFinishSelector:(SEL)finishedSelector; didFinishSelector:(SEL)finishedSelector GTL_NONNULL((1));
#if NS_BLOCKS_AVAILABLE #if NS_BLOCKS_AVAILABLE
- (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL - (GTLServiceTicket *)fetchObjectWithURL:(NSURL *)objectURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut - (GTLServiceTicket *)fetchObjectByInsertingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL forURL:(NSURL *)destinationURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
- (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut - (GTLServiceTicket *)fetchObjectByUpdatingObject:(GTLObject *)bodyToPut
forURL:(NSURL *)destinationURL forURL:(NSURL *)destinationURL
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
- (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL - (GTLServiceTicket *)deleteResourceURL:(NSURL *)destinationURL
ETag:(NSString *)etagOrNil ETag:(NSString *)etagOrNil
completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler; completionHandler:(void (^)(GTLServiceTicket *ticket, id object, NSError *error))handler GTL_NONNULL((1));
#endif #endif
#pragma mark User Properties #pragma mark User Properties
@@ -316,8 +320,8 @@ typedef void *GTLServiceUploadProgressBlock;
// //
// The service properties dictionary is copied to become the initial property // The service properties dictionary is copied to become the initial property
// dictionary for each ticket. // dictionary for each ticket.
- (void)setServiceProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property - (void)setServiceProperty:(id)obj forKey:(NSString *)key GTL_NONNULL((2)); // pass nil obj to remove property
- (id)servicePropertyForKey:(NSString *)key; - (id)servicePropertyForKey:(NSString *)key GTL_NONNULL((1));
@property (nonatomic, copy) NSDictionary *serviceProperties; @property (nonatomic, copy) NSDictionary *serviceProperties;
@@ -350,6 +354,17 @@ typedef void *GTLServiceUploadProgressBlock;
// is ignored. // is ignored.
@property (nonatomic, assign) BOOL shouldFetchInBackground; @property (nonatomic, assign) BOOL shouldFetchInBackground;
// Callbacks can be invoked on an operation queue rather than via the run loop
// starting on 10.7 and iOS 6. Do not specify both run loop modes and an
// operation queue. Specifying a delegate queue typically looks like this:
//
// service.delegateQueue = [[[NSOperationQueue alloc] init] autorelease];
//
// Since the callbacks will be on a thread of the operation queue, the client
// may re-dispatch from the callbacks to a known dispatch queue or to the
// main queue.
@property (nonatomic, retain) NSOperationQueue *delegateQueue;
// Run loop modes are used for scheduling NSURLConnections. // Run loop modes are used for scheduling NSURLConnections.
// //
// The default value, nil, schedules connections using the current run // The default value, nil, schedules connections using the current run
@@ -376,7 +391,7 @@ typedef void *GTLServiceUploadProgressBlock;
// For http method, pass nil (for default GET method), POST, PUT, or DELETE // For http method, pass nil (for default GET method), POST, PUT, or DELETE
- (NSMutableURLRequest *)requestForURL:(NSURL *)url - (NSMutableURLRequest *)requestForURL:(NSURL *)url
ETag:(NSString *)etagOrNil ETag:(NSString *)etagOrNil
httpMethod:(NSString *)httpMethodOrNil; httpMethod:(NSString *)httpMethodOrNil GTL_NONNULL((1));
// objectRequestForURL returns an NSMutableURLRequest for a JSON GTL object // objectRequestForURL returns an NSMutableURLRequest for a JSON GTL object
// //
@@ -388,7 +403,7 @@ typedef void *GTLServiceUploadProgressBlock;
httpMethod:(NSString *)httpMethod httpMethod:(NSString *)httpMethod
isREST:(BOOL)isREST isREST:(BOOL)isREST
additionalHeaders:(NSDictionary *)additionalHeaders additionalHeaders:(NSDictionary *)additionalHeaders
ticket:(GTLServiceTicket *)ticket; ticket:(GTLServiceTicket *)ticket GTL_NONNULL((1));
// The queue used for parsing JSON responses (previously this property // The queue used for parsing JSON responses (previously this property
// was called operationQueue) // was called operationQueue)
@@ -464,7 +479,7 @@ typedef void *GTLServiceUploadProgressBlock;
- (BOOL)waitForTicket:(GTLServiceTicket *)ticket - (BOOL)waitForTicket:(GTLServiceTicket *)ticket
timeout:(NSTimeInterval)timeoutInSeconds timeout:(NSTimeInterval)timeoutInSeconds
fetchedObject:(GTLObject **)outObjectOrNil fetchedObject:(GTLObject **)outObjectOrNil
error:(NSError **)outErrorOrNil; error:(NSError **)outErrorOrNil GTL_NONNULL((1));
@end @end
#pragma mark - #pragma mark -
@@ -540,7 +555,7 @@ typedef void *GTLServiceUploadProgressBlock;
// Properties and userData are supported for client convenience. // Properties and userData are supported for client convenience.
// //
// Property keys beginning with _ are reserved by the library. // Property keys beginning with _ are reserved by the library.
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property - (void)setProperty:(id)obj forKey:(NSString *)key GTL_NONNULL((1)); // pass nil obj to remove property
- (id)propertyForKey:(NSString *)key; - (id)propertyForKey:(NSString *)key;
@property (nonatomic, copy) NSDictionary *properties; @property (nonatomic, copy) NSDictionary *properties;
@@ -552,7 +567,7 @@ typedef void *GTLServiceUploadProgressBlock;
@property (nonatomic, retain) GTLObject *fetchedObject; @property (nonatomic, retain) GTLObject *fetchedObject;
@property (nonatomic, retain) id<GTLQueryProtocol> executingQuery; // Query currently being fetched by this ticket @property (nonatomic, retain) id<GTLQueryProtocol> executingQuery; // Query currently being fetched by this ticket
@property (nonatomic, retain) id<GTLQueryProtocol> originalQuery; // Query used to create this ticket @property (nonatomic, retain) id<GTLQueryProtocol> originalQuery; // Query used to create this ticket
- (GTLQuery *)queryForRequestID:(NSString *)requestID; // Returns the query from within the batch with the given id. - (GTLQuery *)queryForRequestID:(NSString *)requestID GTL_NONNULL((1)); // Returns the query from within the batch with the given id.
@property (nonatomic, retain) NSDictionary *surrogates; @property (nonatomic, retain) NSDictionary *surrogates;

View File

@@ -633,7 +633,10 @@ static NSString *ETagIfPresent(GTLObject *obj) {
if (bodyObject != nil) { if (bodyObject != nil) {
GTL_DEBUG_ASSERT([parameters objectForKey:kBodyObjectParamKey] == nil, GTL_DEBUG_ASSERT([parameters objectForKey:kBodyObjectParamKey] == nil,
@"There was already something under the 'data' key?!"); @"There was already something under the 'data' key?!");
[worker setObject:[bodyObject JSON] forKey:kBodyObjectParamKey]; NSMutableDictionary *json = [bodyObject JSON];
if (json != nil) {
[worker setObject:json forKey:kBodyObjectParamKey];
}
} }
finalParams = worker; finalParams = worker;
} }
@@ -1159,20 +1162,29 @@ totalBytesExpectedToSend:(NSInteger)totalBytesExpected {
SEL parseDoneSel = @selector(handleParsedObjectForFetcher:); SEL parseDoneSel = @selector(handleParsedObjectForFetcher:);
NSArray *runLoopModes = [properties valueForKey:kFetcherCallbackRunLoopModesKey]; NSArray *runLoopModes = [properties valueForKey:kFetcherCallbackRunLoopModesKey];
if (runLoopModes) { // If this callback was enqueued, then the fetcher has already released
// its delegateQueue. We'll use our own delegateQueue to determine how to
// invoke the callbacks.
NSOperationQueue *delegateQueue = self.delegateQueue;
if (delegateQueue) {
NSInvocationOperation *op;
op = [[[NSInvocationOperation alloc] initWithTarget:self
selector:parseDoneSel
object:fetcher] autorelease];
[delegateQueue addOperation:op];
} else if (runLoopModes) {
[self performSelector:parseDoneSel [self performSelector:parseDoneSel
onThread:callbackThread onThread:callbackThread
withObject:fetcher withObject:fetcher
waitUntilDone:NO waitUntilDone:NO
modes:runLoopModes]; modes:runLoopModes];
} else { } else {
// defaults to common modes // Defaults to common modes
[self performSelector:parseDoneSel [self performSelector:parseDoneSel
onThread:callbackThread onThread:callbackThread
withObject:fetcher withObject:fetcher
waitUntilDone:NO]; waitUntilDone:NO];
} }
// the fetcher now belongs to the callback thread // the fetcher now belongs to the callback thread
} }
@@ -2031,6 +2043,14 @@ totalBytesExpectedToSend:(NSInteger)totalBytesExpected {
return self.fetcherService.shouldFetchInBackground; return self.fetcherService.shouldFetchInBackground;
} }
- (void)setDelegateQueue:(NSOperationQueue *)delegateQueue {
self.fetcherService.delegateQueue = delegateQueue;
}
- (NSOperationQueue *)delegateQueue {
return self.fetcherService.delegateQueue;
}
- (void)setRunLoopModes:(NSArray *)array { - (void)setRunLoopModes:(NSArray *)array {
self.fetcherService.runLoopModes = array; self.fetcherService.runLoopModes = array;
} }

View File

@@ -17,6 +17,9 @@
// GTLUploadParameters.h // GTLUploadParameters.h
// //
// Uploading documentation:
// https://code.google.com/p/google-api-objectivec-client/wiki/Introduction#Uploading_Files
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "GTLDefines.h" #import "GTLDefines.h"
@@ -49,9 +52,9 @@
@property (assign) BOOL shouldSendUploadOnly; @property (assign) BOOL shouldSendUploadOnly;
+ (GTLUploadParameters *)uploadParametersWithData:(NSData *)data + (GTLUploadParameters *)uploadParametersWithData:(NSData *)data
MIMEType:(NSString *)mimeType; MIMEType:(NSString *)mimeType GTL_NONNULL((1,2));
+ (GTLUploadParameters *)uploadParametersWithFileHandle:(NSFileHandle *)fileHandle + (GTLUploadParameters *)uploadParametersWithFileHandle:(NSFileHandle *)fileHandle
MIMEType:(NSString *)mimeType; MIMEType:(NSString *)mimeType GTL_NONNULL((1,2));
@end @end

View File

@@ -90,16 +90,4 @@ NSNumber *GTL_EnsureNSNumber(NSNumber *num);
startClass:(Class)startClass startClass:(Class)startClass
ancestorClass:(Class)ancestorClass ancestorClass:(Class)ancestorClass
cache:(NSMutableDictionary *)cache; cache:(NSMutableDictionary *)cache;
//
// MIME Types
//
// Utility routine to convert a file path to the file's MIME type using
// Mac OS X's UTI database
#if !GTL_FOUNDATION_ONLY
+ (NSString *)MIMETypeForFileAtPath:(NSString *)path
defaultMIMEType:(NSString *)defaultType;
#endif
@end @end

View File

@@ -104,7 +104,7 @@ const CFStringRef kCharsToForceEscape = CFSTR("!*'();:@&=+$,/?%#[]");
for (unsigned int idx = 0; utf8[idx] != '\0'; idx++) { for (unsigned int idx = 0; utf8[idx] != '\0'; idx++) {
unsigned char currChar = utf8[idx]; unsigned char currChar = (unsigned char)utf8[idx];
if (currChar < 0x20 || currChar == 0x25 || currChar > 0x7E) { if (currChar < 0x20 || currChar == 0x25 || currChar > 0x7E) {
if (encoded == nil) { if (encoded == nil) {
@@ -300,41 +300,6 @@ const CFStringRef kCharsToForceEscape = CFSTR("!*'();:@&=+$,/?%#[]");
return result; return result;
} }
#pragma mark MIME Types
// Utility routine to convert a file path to the file's MIME type using
// Mac OS X's UTI database
#if !GTL_FOUNDATION_ONLY
+ (NSString *)MIMETypeForFileAtPath:(NSString *)path
defaultMIMEType:(NSString *)defaultType {
NSString *result = defaultType;
// Convert the path to an FSRef
FSRef fileFSRef;
Boolean isDirectory;
OSStatus err = FSPathMakeRef((UInt8 *) [path fileSystemRepresentation],
&fileFSRef, &isDirectory);
if (err == noErr) {
// Get the UTI (content type) for the FSRef
CFStringRef fileUTI;
err = LSCopyItemAttribute(&fileFSRef, kLSRolesAll, kLSItemContentType,
(CFTypeRef *)&fileUTI);
if (err == noErr) {
// Get the MIME type for the UTI
CFStringRef mimeTypeTag;
mimeTypeTag = UTTypeCopyPreferredTagWithClass(fileUTI,
kUTTagClassMIMEType);
if (mimeTypeTag) {
// Convert the CFStringRef to an autoreleased NSString
result = [(id)CFMakeCollectable(mimeTypeTag) autorelease];
}
CFRelease(fileUTI);
}
}
return result;
}
#endif
@end @end
// isEqual: has the fatal flaw that it doesn't deal well with the receiver // isEqual: has the fatal flaw that it doesn't deal well with the receiver
@@ -357,19 +322,36 @@ BOOL GTL_AreBoolsEqual(BOOL b1, BOOL b2) {
} }
NSNumber *GTL_EnsureNSNumber(NSNumber *num) { NSNumber *GTL_EnsureNSNumber(NSNumber *num) {
// If the server returned a string object where we expect a number, try
// to make a number object.
if ([num isKindOfClass:[NSString class]]) { if ([num isKindOfClass:[NSString class]]) {
NSDecimalNumber *reallyNum; NSNumber *newNum;
// Force the parse to use '.' as the number seperator. NSString *str = (NSString *)num;
static NSLocale *usLocale = nil; if ([str rangeOfString:@"."].location != NSNotFound) {
@synchronized([GTLUtilities class]) { // This is a floating-point number.
if (usLocale == nil) { // Force the parser to use '.' as the decimal separator.
usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; static NSLocale *usLocale = nil;
@synchronized([GTLUtilities class]) {
if (usLocale == nil) {
usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
}
newNum = [NSDecimalNumber decimalNumberWithString:(NSString*)num
locale:(id)usLocale];
}
} else {
// NSDecimalNumber +decimalNumberWithString:locale:
// does not correctly create an NSNumber for large values like
// 71100000000007780.
if ([str hasPrefix:@"-"]) {
newNum = [NSNumber numberWithLongLong:[str longLongValue]];
} else {
const char *utf8 = [str UTF8String];
unsigned long long ull = strtoull(utf8, NULL, 10);
newNum = [NSNumber numberWithUnsignedLongLong:ull];
} }
reallyNum = [NSDecimalNumber decimalNumberWithString:(NSString*)num
locale:(id)usLocale];
} }
if (reallyNum != nil) { if (newNum) {
num = reallyNum; num = newNum;
} }
} }
return num; return num;

View File

@@ -21,9 +21,13 @@
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
#include <TargetConditionals.h> #include <TargetConditionals.h>
#ifdef __OBJC__
#include <Foundation/NSObjCRuntime.h>
#endif // __OBJC__
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
#include <Availability.h> #include <Availability.h>
#endif // TARGET_OS_IPHONE #endif // TARGET_OS_IPHONE
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs // Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
#ifndef MAC_OS_X_VERSION_10_5 #ifndef MAC_OS_X_VERSION_10_5
@@ -213,21 +217,10 @@
#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE #define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE
#endif #endif
// Provide a symbol to include/exclude extra code for GC support. (This mainly // GC was dropped by Apple, define the old constant incase anyone still keys
// just controls the inclusion of finalize methods). // off of it.
#ifndef GTM_SUPPORT_GC #ifndef GTM_SUPPORT_GC
#if GTM_IPHONE_SDK #define GTM_SUPPORT_GC 0
// iPhone never needs GC
#define GTM_SUPPORT_GC 0
#else
// We can't find a symbol to tell if GC is supported/required, so best we
// do on Mac targets is include it if we're on 10.5 or later.
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define GTM_SUPPORT_GC 0
#else
#define GTM_SUPPORT_GC 1
#endif
#endif
#endif #endif
// To simplify support for 64bit (and Leopard in general), we provide the type // To simplify support for 64bit (and Leopard in general), we provide the type
@@ -348,7 +341,15 @@
#endif #endif
#ifndef GTM_NONNULL #ifndef GTM_NONNULL
#define GTM_NONNULL(x) __attribute__((nonnull(x))) #if defined(__has_attribute)
#if __has_attribute(nonnull)
#define GTM_NONNULL(x) __attribute__((nonnull x))
#else
#define GTM_NONNULL(x)
#endif
#else
#define GTM_NONNULL(x)
#endif
#endif #endif
// Invalidates the initializer from which it's called. // Invalidates the initializer from which it's called.
@@ -356,6 +357,7 @@
#if __has_feature(objc_arc) #if __has_feature(objc_arc)
#define GTMInvalidateInitializer() \ #define GTMInvalidateInitializer() \
do { \ do { \
[self class]; /* Avoid warning of dead store to |self|. */ \
_GTMDevAssert(NO, @"Invalid initializer."); \ _GTMDevAssert(NO, @"Invalid initializer."); \
return nil; \ return nil; \
} while (0) } while (0)
@@ -436,4 +438,4 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,
#endif // DEBUG #endif // DEBUG
#endif // GTM_SEL_STRING #endif // GTM_SEL_STRING
#endif // __OBJC__ #endif // __OBJC__

View File

@@ -40,10 +40,10 @@ static NSString* const kGTMETagHeader = @"Etag";
[super dealloc]; [super dealloc];
} }
// add all cookies in the new cookie array to the storage, // Add all cookies in the new cookie array to the storage,
// replacing stored cookies as appropriate // replacing stored cookies as appropriate.
// //
// Side effect: removes expired cookies from the storage array // Side effect: removes expired cookies from the storage array.
- (void)setCookies:(NSArray *)newCookies { - (void)setCookies:(NSArray *)newCookies {
@synchronized(cookies_) { @synchronized(cookies_) {
@@ -82,9 +82,9 @@ static NSString* const kGTMETagHeader = @"Etag";
} }
} }
// retrieve all cookies appropriate for the given URL, considering // Retrieve all cookies appropriate for the given URL, considering
// domain, path, cookie name, expiration, security setting. // domain, path, cookie name, expiration, security setting.
// Side effect: removed expired cookies from the storage array // Side effect: removed expired cookies from the storage array.
- (NSArray *)cookiesForURL:(NSURL *)theURL { - (NSArray *)cookiesForURL:(NSURL *)theURL {
NSMutableArray *foundCookies = nil; NSMutableArray *foundCookies = nil;
@@ -92,9 +92,9 @@ static NSString* const kGTMETagHeader = @"Etag";
@synchronized(cookies_) { @synchronized(cookies_) {
[self removeExpiredCookies]; [self removeExpiredCookies];
// we'll prepend "." to the desired domain, since we want the // We'll prepend "." to the desired domain, since we want the
// actual domain "nytimes.com" to still match the cookie domain // actual domain "nytimes.com" to still match the cookie domain
// ".nytimes.com" when we check it below with hasSuffix // ".nytimes.com" when we check it below with hasSuffix.
NSString *host = [[theURL host] lowercaseString]; NSString *host = [[theURL host] lowercaseString];
NSString *path = [theURL path]; NSString *path = [theURL path];
NSString *scheme = [theURL scheme]; NSString *scheme = [theURL scheme];
@@ -144,13 +144,13 @@ static NSString* const kGTMETagHeader = @"Etag";
return foundCookies; return foundCookies;
} }
// return a cookie from the array with the same name, domain, and path as the // Return a cookie from the array with the same name, domain, and path as the
// given cookie, or else return nil if none found // given cookie, or else return nil if none found.
// //
// Both the cookie being tested and all cookies in the storage array should // Both the cookie being tested and all cookies in the storage array should
// be valid (non-nil name, domains, paths) // be valid (non-nil name, domains, paths).
// //
// note: this should only be called from inside a @synchronized(cookies_) block // Note: this should only be called from inside a @synchronized(cookies_) block
- (NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { - (NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie {
NSUInteger numberOfCookies = [cookies_ count]; NSUInteger numberOfCookies = [cookies_ count];
@@ -176,20 +176,20 @@ static NSString* const kGTMETagHeader = @"Etag";
} }
// internal routine to remove any expired cookies from the array, excluding // Internal routine to remove any expired cookies from the array, excluding
// cookies with nil expirations // cookies with nil expirations.
// //
// note: this should only be called from inside a @synchronized(cookies_) block // Note: this should only be called from inside a @synchronized(cookies_) block
- (void)removeExpiredCookies { - (void)removeExpiredCookies {
// count backwards since we're deleting items from the array // count backwards since we're deleting items from the array
for (NSInteger idx = [cookies_ count] - 1; idx >= 0; idx--) { for (NSInteger idx = (NSInteger)[cookies_ count] - 1; idx >= 0; idx--) {
NSHTTPCookie *storedCookie = [cookies_ objectAtIndex:idx]; NSHTTPCookie *storedCookie = [cookies_ objectAtIndex:(NSUInteger)idx];
NSDate *expiresDate = [storedCookie expiresDate]; NSDate *expiresDate = [storedCookie expiresDate];
if (expiresDate && [expiresDate timeIntervalSinceNow] < 0) { if (expiresDate && [expiresDate timeIntervalSinceNow] < 0) {
[cookies_ removeObjectAtIndex:idx]; [cookies_ removeObjectAtIndex:(NSUInteger)idx];
} }
} }
} }
@@ -281,18 +281,18 @@ static NSString* const kGTMETagHeader = @"Etag";
[self class], self, [responses_ allValues]]; [self class], self, [responses_ allValues]];
} }
// setters/getters // Setters/getters
- (void)pruneCacheResponses { - (void)pruneCacheResponses {
// internal routine to remove the least-recently-used responses when the // Internal routine to remove the least-recently-used responses when the
// cache has grown too large // cache has grown too large
if (memoryCapacity_ >= totalDataSize_) return; if (memoryCapacity_ >= totalDataSize_) return;
// sort keys by date // Sort keys by date
SEL sel = @selector(compareUseDate:); SEL sel = @selector(compareUseDate:);
NSArray *sortedKeys = [responses_ keysSortedByValueUsingSelector:sel]; NSArray *sortedKeys = [responses_ keysSortedByValueUsingSelector:sel];
// the least-recently-used keys are at the beginning of the sorted array; // The least-recently-used keys are at the beginning of the sorted array;
// remove those (except ones still reserved) until the total data size is // remove those (except ones still reserved) until the total data size is
// reduced sufficiently // reduced sufficiently
for (NSURL *key in sortedKeys) { for (NSURL *key in sortedKeys) {
@@ -303,13 +303,13 @@ static NSString* const kGTMETagHeader = @"Etag";
&& ([resDate timeIntervalSinceNow] > -reservationInterval_); && ([resDate timeIntervalSinceNow] > -reservationInterval_);
if (!isResponseReserved) { if (!isResponseReserved) {
// we can remove this response from the cache // We can remove this response from the cache
NSUInteger storedSize = [[response data] length]; NSUInteger storedSize = [[response data] length];
totalDataSize_ -= storedSize; totalDataSize_ -= storedSize;
[responses_ removeObjectForKey:key]; [responses_ removeObjectForKey:key];
} }
// if we've removed enough response data, then we're done // If we've removed enough response data, then we're done
if (memoryCapacity_ >= totalDataSize_) break; if (memoryCapacity_ >= totalDataSize_) break;
} }
} }
@@ -317,7 +317,7 @@ static NSString* const kGTMETagHeader = @"Etag";
- (void)storeCachedResponse:(GTMCachedURLResponse *)cachedResponse - (void)storeCachedResponse:(GTMCachedURLResponse *)cachedResponse
forRequest:(NSURLRequest *)request { forRequest:(NSURLRequest *)request {
@synchronized(self) { @synchronized(self) {
// remove any previous entry for this request // Remove any previous entry for this request
[self removeCachedResponseForRequest:request]; [self removeCachedResponseForRequest:request];
// cache this one only if it's not bigger than our cache // cache this one only if it's not bigger than our cache
@@ -340,7 +340,7 @@ static NSString* const kGTMETagHeader = @"Etag";
NSURL *key = [request URL]; NSURL *key = [request URL];
response = [[[responses_ objectForKey:key] retain] autorelease]; response = [[[responses_ objectForKey:key] retain] autorelease];
// touch the date to indicate this was recently retrieved // Touch the date to indicate this was recently retrieved
[response setUseDate:[NSDate date]]; [response setUseDate:[NSDate date]];
} }
return response; return response;
@@ -376,7 +376,7 @@ static NSString* const kGTMETagHeader = @"Etag";
} }
} }
// methods for unit testing // Methods for unit testing.
- (void)setReservationInterval:(NSTimeInterval)secs { - (void)setReservationInterval:(NSTimeInterval)secs {
reservationInterval_ = secs; reservationInterval_ = secs;
} }
@@ -432,32 +432,34 @@ static NSString* const kGTMETagHeader = @"Etag";
} }
- (void)updateRequest:(NSMutableURLRequest *)request isHTTPGet:(BOOL)isHTTPGet { - (void)updateRequest:(NSMutableURLRequest *)request isHTTPGet:(BOOL)isHTTPGet {
if ([self shouldRememberETags]) { @synchronized(self) {
// If this URL is in the history, and no ETag has been set, then if ([self shouldRememberETags]) {
// set the ETag header field // If this URL is in the history, and no ETag has been set, then
// set the ETag header field
// if we have a history, we're tracking across fetches, so we don't // If we have a history, we're tracking across fetches, so we don't
// want to pull results from any other cache // want to pull results from any other cache
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData]; [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
if (isHTTPGet) { if (isHTTPGet) {
// we'll only add an ETag if there's no ETag specified in the user's // We'll only add an ETag if there's no ETag specified in the user's
// request // request
NSString *specifiedETag = [request valueForHTTPHeaderField:kGTMIfNoneMatchHeader]; NSString *specifiedETag = [request valueForHTTPHeaderField:kGTMIfNoneMatchHeader];
if (specifiedETag == nil) { if (specifiedETag == nil) {
// no ETag: extract the previous ETag for this request from the // No ETag: extract the previous ETag for this request from the
// fetch history, and add it to the request // fetch history, and add it to the request
NSString *cachedETag = [self cachedETagForRequest:request]; NSString *cachedETag = [self cachedETagForRequest:request];
if (cachedETag != nil) { if (cachedETag != nil) {
[request addValue:cachedETag forHTTPHeaderField:kGTMIfNoneMatchHeader]; [request addValue:cachedETag forHTTPHeaderField:kGTMIfNoneMatchHeader];
}
} else {
// Has an ETag: remove any stored response in the fetch history
// for this request, as the If-None-Match header could lead to
// a 304 Not Modified, and we want that error delivered to the
// user since they explicitly specified the ETag
[self removeCachedDataForRequest:request];
} }
} else {
// has an ETag: remove any stored response in the fetch history
// for this request, as the If-None-Match header could lead to
// a 304 Not Modified, and we want that error delivered to the
// user since they explicitly specified the ETag
[self removeCachedDataForRequest:request];
} }
} }
} }
@@ -466,38 +468,41 @@ static NSString* const kGTMETagHeader = @"Etag";
- (void)updateFetchHistoryWithRequest:(NSURLRequest *)request - (void)updateFetchHistoryWithRequest:(NSURLRequest *)request
response:(NSURLResponse *)response response:(NSURLResponse *)response
downloadedData:(NSData *)downloadedData { downloadedData:(NSData *)downloadedData {
if (![self shouldRememberETags]) return; @synchronized(self) {
if (![self shouldRememberETags]) return;
if (![response respondsToSelector:@selector(allHeaderFields)]) return; if (![response respondsToSelector:@selector(allHeaderFields)]) return;
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != kGTMHTTPFetcherStatusNotModified) { if (statusCode != kGTMHTTPFetcherStatusNotModified) {
// save this ETag string for successful results (<300) // Save this ETag string for successful results (<300)
// If there's no last modified string, clear the dictionary // If there's no last modified string, clear the dictionary
// entry for this URL. Also cache or delete the data, if appropriate // entry for this URL. Also cache or delete the data, if appropriate
// (when etaggedDataCache is non-nil.) // (when etaggedDataCache is non-nil.)
NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields];
NSString* etag = [headers objectForKey:kGTMETagHeader]; NSString* etag = [headers objectForKey:kGTMETagHeader];
if (etag != nil && statusCode < 300) { if (etag != nil && statusCode < 300) {
// we want to cache responses for the headers, even if the client // we want to cache responses for the headers, even if the client
// doesn't want the response body data caches // doesn't want the response body data caches
NSData *dataToStore = shouldCacheETaggedData_ ? downloadedData : nil; NSData *dataToStore = shouldCacheETaggedData_ ? downloadedData : nil;
GTMCachedURLResponse *cachedResponse; GTMCachedURLResponse *cachedResponse;
cachedResponse = [[[GTMCachedURLResponse alloc] initWithResponse:response cachedResponse = [[[GTMCachedURLResponse alloc] initWithResponse:response
data:dataToStore] autorelease]; data:dataToStore] autorelease];
[etaggedDataCache_ storeCachedResponse:cachedResponse [etaggedDataCache_ storeCachedResponse:cachedResponse
forRequest:request]; forRequest:request];
} else { } else {
[etaggedDataCache_ removeCachedResponseForRequest:request]; [etaggedDataCache_ removeCachedResponseForRequest:request];
}
} }
} }
} }
- (NSString *)cachedETagForRequest:(NSURLRequest *)request { - (NSString *)cachedETagForRequest:(NSURLRequest *)request {
// Internal routine.
GTMCachedURLResponse *cachedResponse; GTMCachedURLResponse *cachedResponse;
cachedResponse = [etaggedDataCache_ cachedResponseForRequest:request]; cachedResponse = [etaggedDataCache_ cachedResponseForRequest:request];
@@ -505,46 +510,56 @@ static NSString* const kGTMETagHeader = @"Etag";
NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields];
NSString *cachedETag = [headers objectForKey:kGTMETagHeader]; NSString *cachedETag = [headers objectForKey:kGTMETagHeader];
if (cachedETag) { if (cachedETag) {
// since the request having an ETag implies this request is about // Since the request having an ETag implies this request is about
// to be fetched again, reserve the cached response to ensure that // to be fetched again, reserve the cached response to ensure that
// that it will be around at least until the fetch completes // that it will be around at least until the fetch completes.
// //
// when the fetch completes, either the cached response will be replaced // When the fetch completes, either the cached response will be replaced
// with a new response, or the cachedDataForRequest: method below will // with a new response, or the cachedDataForRequest: method below will
// clear the reservation // clear the reservation.
[cachedResponse setReservationDate:[NSDate date]]; [cachedResponse setReservationDate:[NSDate date]];
} }
return cachedETag; return cachedETag;
} }
- (NSData *)cachedDataForRequest:(NSURLRequest *)request { - (NSData *)cachedDataForRequest:(NSURLRequest *)request {
GTMCachedURLResponse *cachedResponse; @synchronized(self) {
cachedResponse = [etaggedDataCache_ cachedResponseForRequest:request]; GTMCachedURLResponse *cachedResponse;
cachedResponse = [etaggedDataCache_ cachedResponseForRequest:request];
NSData *cachedData = [cachedResponse data]; NSData *cachedData = [cachedResponse data];
// since the data for this cached request is being obtained from the cache, // Since the data for this cached request is being obtained from the cache,
// we can clear the reservation as the fetch has completed // we can clear the reservation as the fetch has completed.
[cachedResponse setReservationDate:nil]; [cachedResponse setReservationDate:nil];
return cachedData; return cachedData;
}
} }
- (void)removeCachedDataForRequest:(NSURLRequest *)request { - (void)removeCachedDataForRequest:(NSURLRequest *)request {
[etaggedDataCache_ removeCachedResponseForRequest:request]; @synchronized(self) {
[etaggedDataCache_ removeCachedResponseForRequest:request];
}
} }
- (void)clearETaggedDataCache { - (void)clearETaggedDataCache {
[etaggedDataCache_ removeAllCachedResponses]; @synchronized(self) {
[etaggedDataCache_ removeAllCachedResponses];
}
} }
- (void)clearHistory { - (void)clearHistory {
[self clearETaggedDataCache]; @synchronized(self) {
[cookieStorage_ removeAllCookies]; [self clearETaggedDataCache];
[cookieStorage_ removeAllCookies];
}
} }
- (void)removeAllCookies { - (void)removeAllCookies {
[cookieStorage_ removeAllCookies]; @synchronized(self) {
[cookieStorage_ removeAllCookies];
}
} }
- (BOOL)shouldRememberETags { - (BOOL)shouldRememberETags {
@@ -556,7 +571,7 @@ static NSString* const kGTMETagHeader = @"Etag";
shouldRememberETags_ = flag; shouldRememberETags_ = flag;
if (wasRemembering && !flag) { if (wasRemembering && !flag) {
// free up the cache memory // Free up the cache memory
[self clearETaggedDataCache]; [self clearETaggedDataCache];
} }
} }

View File

@@ -77,6 +77,33 @@
// Status codes are at <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html> // 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:
//
// fetcher.delegateQueue = [[[NSOperationQueue alloc] init] autorelease];
//
// 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: // Downloading to disk:
// //
// To have downloaded data saved directly to disk, specify either a path for the // To have downloaded data saved directly to disk, specify either a path for the
@@ -343,6 +370,9 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
@protocol GTMHTTPFetcherServiceProtocol <NSObject> @protocol GTMHTTPFetcherServiceProtocol <NSObject>
// This protocol allows us to call into the service without requiring // This protocol allows us to call into the service without requiring
// GTMHTTPFetcherService sources in this project // GTMHTTPFetcherService sources in this project
@property (retain) NSOperationQueue *delegateQueue;
- (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher; - (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher;
- (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher; - (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher;
@@ -360,6 +390,8 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
- (void)stopAuthorization; - (void)stopAuthorization;
- (void)stopAuthorizationForRequest:(NSURLRequest *)request;
- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; - (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; - (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
@@ -416,7 +448,8 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
#endif #endif
id userData_; // retained, if set by caller id userData_; // retained, if set by caller
NSMutableDictionary *properties_; // more data retained for caller NSMutableDictionary *properties_; // more data retained for caller
NSArray *runLoopModes_; // optional, for 10.5 and later 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 id <GTMHTTPFetchHistoryProtocol> fetchHistory_; // if supplied by the caller, used for Last-Modified-Since checks and cookies
NSInteger cookieStorageMethod_; // constant from above NSInteger cookieStorageMethod_; // constant from above
id <GTMCookieStorageProtocol> cookieStorage_; id <GTMCookieStorageProtocol> cookieStorage_;
@@ -441,6 +474,11 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
NSString *comment_; // comment for log NSString *comment_; // comment for log
NSString *log_; NSString *log_;
#if !STRIP_GTM_FETCH_LOGGING
NSString *logRequestBody_;
NSString *logResponseBody_;
BOOL shouldDeferResponseBodyLogging_;
#endif
} }
// Create a fetcher // Create a fetcher
@@ -502,7 +540,8 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
// fetchers that are being delayed by a fetcher service. // fetchers that are being delayed by a fetcher service.
@property (assign) NSInteger servicePriority; @property (assign) NSInteger servicePriority;
// The thread used to run this fetcher in the fetcher service // The thread used to run this fetcher in the fetcher service when no operation
// queue is provided.
@property (retain) NSThread *thread; @property (retain) NSThread *thread;
// The delegate is retained during the connection // The delegate is retained during the connection
@@ -672,11 +711,16 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
// Comments are useful for logging // Comments are useful for logging
@property (copy) NSString *comment; @property (copy) NSString *comment;
- (void)setCommentWithFormat:(id)format, ...; - (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
// Log of request and response, if logging is enabled // Log of request and response, if logging is enabled
@property (copy) NSString *log; @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 // Using the fetcher while a modal dialog is displayed requires setting the
// run-loop modes to include NSModalPanelRunLoopMode // run-loop modes to include NSModalPanelRunLoopMode
@property (retain) NSArray *runLoopModes; @property (retain) NSArray *runLoopModes;

File diff suppressed because it is too large Load Diff

View File

@@ -80,6 +80,19 @@
// internal; called by fetcher // internal; called by fetcher
- (void)logFetchWithError:(NSError *)error; - (void)logFetchWithError:(NSError *)error;
- (BOOL)logCapturePostStream; - (BOOL)logCapturePostStream;
// Applications may provide alternative body strings to be displayed in the
// log, such as for binary requests or responses. If deferring is turned
// on, the response log will not be sent until deferring is turned off,
// allowing the application to write the response body after the response
// data has been parsed.
- (void)setLogRequestBody:(NSString *)bodyString;
- (NSString *)logRequestBody;
- (void)setLogResponseBody:(NSString *)bodyString;
- (NSString *)logResponseBody;
- (void)setShouldDeferResponseBodyLogging:(BOOL)flag;
- (BOOL)shouldDeferResponseBodyLogging;
@end @end
#endif #endif // !STRIP_GTM_FETCH_LOGGING

View File

@@ -40,10 +40,13 @@
@end @end
// If GTMNSJSONSerialization is available, it is used for formatting JSON // If GTMNSJSONSerialization is available, it is used for formatting JSON
#if (TARGET_OS_MAC && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED < 1070)) || \
(TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED < 50000))
@interface GTMNSJSONSerialization : NSObject @interface GTMNSJSONSerialization : NSObject
+ (NSData *)dataWithJSONObject:(id)obj options:(NSUInteger)opt error:(NSError **)error; + (NSData *)dataWithJSONObject:(id)obj options:(NSUInteger)opt error:(NSError **)error;
+ (id)JSONObjectWithData:(NSData *)data options:(NSUInteger)opt error:(NSError **)error; + (id)JSONObjectWithData:(NSData *)data options:(NSUInteger)opt error:(NSError **)error;
@end @end
#endif
// Otherwise, if SBJSON is available, it is used for formatting JSON // Otherwise, if SBJSON is available, it is used for formatting JSON
@interface GTMFetcherSBJSON @interface GTMFetcherSBJSON
@@ -291,6 +294,51 @@ static NSString* gLoggingProcessName = nil;
} }
} }
- (void)setLogRequestBody:(NSString *)bodyString {
@synchronized(self) {
[logRequestBody_ release];
logRequestBody_ = [bodyString copy];
}
}
- (NSString *)logRequestBody {
@synchronized(self) {
return logRequestBody_;
}
}
- (void)setLogResponseBody:(NSString *)bodyString {
@synchronized(self) {
[logResponseBody_ release];
logResponseBody_ = [bodyString copy];
}
}
- (NSString *)logResponseBody {
@synchronized(self) {
return logResponseBody_;
}
}
- (void)setShouldDeferResponseBodyLogging:(BOOL)flag {
@synchronized(self) {
if (flag != shouldDeferResponseBodyLogging_) {
shouldDeferResponseBodyLogging_ = flag;
if (!flag) {
[self performSelectorOnMainThread:@selector(logFetchWithError:)
withObject:nil
waitUntilDone:NO];
}
}
}
}
- (BOOL)shouldDeferResponseBodyLogging {
@synchronized(self) {
return shouldDeferResponseBodyLogging_;
}
}
// stringFromStreamData creates a string given the supplied data // stringFromStreamData creates a string given the supplied data
// //
// If NSString can create a UTF-8 string from the data, then that is returned. // If NSString can create a UTF-8 string from the data, then that is returned.
@@ -525,16 +573,16 @@ static NSString* gLoggingProcessName = nil;
// write the date & time, the comment, and the link to the plain-text // write the date & time, the comment, and the link to the plain-text
// (copyable) log // (copyable) log
NSString *dateLineFormat = @"<b>%@ &nbsp;&nbsp;&nbsp;&nbsp; "; NSString *const dateLineFormat = @"<b>%@ &nbsp;&nbsp;&nbsp;&nbsp; ";
[outputHTML appendFormat:dateLineFormat, [NSDate date]]; [outputHTML appendFormat:dateLineFormat, [NSDate date]];
NSString *comment = [self comment]; NSString *comment = [self comment];
if (comment) { if (comment) {
NSString *commentFormat = @"%@ &nbsp;&nbsp;&nbsp;&nbsp; "; NSString *const commentFormat = @"%@ &nbsp;&nbsp;&nbsp;&nbsp; ";
[outputHTML appendFormat:commentFormat, comment]; [outputHTML appendFormat:commentFormat, comment];
} }
NSString *reqRespFormat = @"</b><a href='%@'><i>request/response log</i></a><br>"; NSString *const reqRespFormat = @"</b><a href='%@'><i>request/response log</i></a><br>";
[outputHTML appendFormat:reqRespFormat, copyableFileName]; [outputHTML appendFormat:reqRespFormat, copyableFileName];
// write the request URL // write the request URL
@@ -598,22 +646,28 @@ static NSString* gLoggingProcessName = nil;
[outputHTML appendFormat:@"&nbsp;&nbsp; data: %d bytes, <code>%@</code><br>\n", [outputHTML appendFormat:@"&nbsp;&nbsp; data: %d bytes, <code>%@</code><br>\n",
(int)postDataLength, postType ? postType : @"<no type>"]; (int)postDataLength, postType ? postType : @"<no type>"];
postDataStr = [self stringFromStreamData:postData if (logRequestBody_) {
contentType:postType]; postDataStr = [[logRequestBody_ copy] autorelease];
if (postDataStr) { [logRequestBody_ release];
// remove OAuth 2 client secret and refresh token logRequestBody_ = nil;
postDataStr = [[self class] snipSubstringOfString:postDataStr } else {
betweenStartString:@"client_secret=" postDataStr = [self stringFromStreamData:postData
endString:@"&"]; contentType:postType];
if (postDataStr) {
// remove OAuth 2 client secret and refresh token
postDataStr = [[self class] snipSubstringOfString:postDataStr
betweenStartString:@"client_secret="
endString:@"&"];
postDataStr = [[self class] snipSubstringOfString:postDataStr postDataStr = [[self class] snipSubstringOfString:postDataStr
betweenStartString:@"refresh_token=" betweenStartString:@"refresh_token="
endString:@"&"]; endString:@"&"];
// remove ClientLogin password // remove ClientLogin password
postDataStr = [[self class] snipSubstringOfString:postDataStr postDataStr = [[self class] snipSubstringOfString:postDataStr
betweenStartString:@"&Passwd=" betweenStartString:@"&Passwd="
endString:@"&"]; endString:@"&"];
}
} }
} else { } else {
// no post data // no post data
@@ -634,7 +688,7 @@ static NSString* gLoggingProcessName = nil;
NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; NSString *jsonCode = [[jsonError valueForKey:@"code"] description];
NSString *jsonMessage = [jsonError valueForKey:@"message"]; NSString *jsonMessage = [jsonError valueForKey:@"message"];
if (jsonCode || jsonMessage) { if (jsonCode || jsonMessage) {
NSString *jsonErrFmt = @"&nbsp;&nbsp;&nbsp;<i>JSON error:</i> <FONT" NSString *const jsonErrFmt = @"&nbsp;&nbsp;&nbsp;<i>JSON error:</i> <FONT"
@" COLOR='#FF00FF'>%@ %@ &nbsp;&#x2691;</FONT>"; // 2691 = @" COLOR='#FF00FF'>%@ %@ &nbsp;&#x2691;</FONT>"; // 2691 =
statusString = [statusString stringByAppendingFormat:jsonErrFmt, statusString = [statusString stringByAppendingFormat:jsonErrFmt,
jsonCode ? jsonCode : @"", jsonCode ? jsonCode : @"",
@@ -645,7 +699,7 @@ static NSString* gLoggingProcessName = nil;
} else { } else {
// purple for anything other than 200 or 201 // purple for anything other than 200 or 201
NSString *flag = (status >= 400 ? @"&nbsp;&#x2691;" : @""); // 2691 = NSString *flag = (status >= 400 ? @"&nbsp;&#x2691;" : @""); // 2691 =
NSString *statusFormat = @"<FONT COLOR='#FF00FF'>%ld %@</FONT>"; NSString *const statusFormat = @"<FONT COLOR='#FF00FF'>%ld %@</FONT>";
statusString = [NSString stringWithFormat:statusFormat, statusString = [NSString stringWithFormat:statusFormat,
(long)status, flag]; (long)status, flag];
} }
@@ -656,7 +710,7 @@ static NSString* gLoggingProcessName = nil;
NSURL *responseURL = [response URL]; NSURL *responseURL = [response URL];
if (responseURL && ![responseURL isEqual:[request URL]]) { if (responseURL && ![responseURL isEqual:[request URL]]) {
NSString *responseURLFormat = @"<FONT COLOR='#FF00FF'>response URL:" NSString *const responseURLFormat = @"<FONT COLOR='#FF00FF'>response URL:"
"</FONT> <code>%@</code><br>\n"; "</FONT> <code>%@</code><br>\n";
responseURLStr = [NSString stringWithFormat:responseURLFormat, responseURLStr = [NSString stringWithFormat:responseURLFormat,
[responseURL absoluteString]]; [responseURL absoluteString]];
@@ -697,13 +751,13 @@ static NSString* gLoggingProcessName = nil;
// Make a small inline image that links to the full image file // Make a small inline image that links to the full image file
[outputHTML appendFormat:@"&nbsp;&nbsp; data: %d bytes, <code>%@</code><br>", [outputHTML appendFormat:@"&nbsp;&nbsp; data: %d bytes, <code>%@</code><br>",
(int)responseDataLength, responseMIMEType]; (int)responseDataLength, responseMIMEType];
NSString *fmt = @"<a href=\"%@\"><img src='%@' alt='image'" NSString *const fmt = @"<a href=\"%@\"><img src='%@' alt='image'"
" style='border:solid thin;max-height:32'></a>\n"; " style='border:solid thin;max-height:32'></a>\n";
[outputHTML appendFormat:fmt, [outputHTML appendFormat:fmt,
escapedResponseFile, escapedResponseFile]; escapedResponseFile, escapedResponseFile];
} else { } else {
// The response data was XML; link to the xml file // The response data was XML; link to the xml file
NSString *fmt = @"&nbsp;&nbsp; data: %d bytes, <code>" NSString *const fmt = @"&nbsp;&nbsp; data: %d bytes, <code>"
"%@</code>&nbsp;&nbsp;&nbsp;<i><a href=\"%@\">%@</a></i>\n"; "%@</code>&nbsp;&nbsp;&nbsp;<i><a href=\"%@\">%@</a></i>\n";
[outputHTML appendFormat:fmt, [outputHTML appendFormat:fmt,
(int)responseDataLength, responseMIMEType, (int)responseDataLength, responseMIMEType,
@@ -744,6 +798,11 @@ static NSString* gLoggingProcessName = nil;
[copyable appendFormat:@"Response body: (%u bytes)\n", [copyable appendFormat:@"Response body: (%u bytes)\n",
(unsigned int) responseDataLength]; (unsigned int) responseDataLength];
if (responseDataLength > 0) { if (responseDataLength > 0) {
if (logResponseBody_) {
responseDataStr = [[logResponseBody_ copy] autorelease];
[logResponseBody_ release];
logResponseBody_ = nil;
}
if (responseDataStr != nil) { if (responseDataStr != nil) {
[copyable appendFormat:@"%@\n", responseDataStr]; [copyable appendFormat:@"%@\n", responseDataStr];
} else if (status >= 400 && [temporaryDownloadPath_ length] > 0) { } else if (status >= 400 && [temporaryDownloadPath_ length] > 0) {

View File

@@ -42,6 +42,7 @@
NSUInteger maxRunningFetchersPerHost_; NSUInteger maxRunningFetchersPerHost_;
GTMHTTPFetchHistory *fetchHistory_; GTMHTTPFetchHistory *fetchHistory_;
NSOperationQueue *delegateQueue_;
NSArray *runLoopModes_; NSArray *runLoopModes_;
NSString *userAgent_; NSString *userAgent_;
NSTimeInterval timeout_; NSTimeInterval timeout_;
@@ -83,12 +84,18 @@
- (NSUInteger)numberOfRunningFetchers; - (NSUInteger)numberOfRunningFetchers;
- (NSUInteger)numberOfDelayedFetchers; - (NSUInteger)numberOfDelayedFetchers;
// Search for running or delayed fetchers with the specified URL.
//
// Returns an array of fetcher objects found, or nil if none found.
- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL;
- (void)stopAllFetchers; - (void)stopAllFetchers;
// Properties to be applied to each fetcher; // Properties to be applied to each fetcher;
// see GTMHTTPFetcher.h for descriptions // see GTMHTTPFetcher.h for descriptions
@property (copy) NSString *userAgent; @property (copy) NSString *userAgent;
@property (assign) NSTimeInterval timeout; @property (assign) NSTimeInterval timeout;
@property (retain) NSOperationQueue *delegateQueue;
@property (retain) NSArray *runLoopModes; @property (retain) NSArray *runLoopModes;
@property (retain) NSURLCredential *credential; @property (retain) NSURLCredential *credential;
@property (retain) NSURLCredential *proxyCredential; @property (retain) NSURLCredential *proxyCredential;

View File

@@ -36,6 +36,7 @@
@synthesize maxRunningFetchersPerHost = maxRunningFetchersPerHost_, @synthesize maxRunningFetchersPerHost = maxRunningFetchersPerHost_,
userAgent = userAgent_, userAgent = userAgent_,
timeout = timeout_, timeout = timeout_,
delegateQueue = delegateQueue_,
runLoopModes = runLoopModes_, runLoopModes = runLoopModes_,
credential = credential_, credential = credential_,
proxyCredential = proxyCredential_, proxyCredential = proxyCredential_,
@@ -63,6 +64,7 @@
[runningHosts_ release]; [runningHosts_ release];
[fetchHistory_ release]; [fetchHistory_ release];
[userAgent_ release]; [userAgent_ release];
[delegateQueue_ release];
[runLoopModes_ release]; [runLoopModes_ release];
[credential_ release]; [credential_ release];
[proxyCredential_ release]; [proxyCredential_ release];
@@ -78,6 +80,7 @@
GTMHTTPFetcher *fetcher = [fetcherClass fetcherWithRequest:request]; GTMHTTPFetcher *fetcher = [fetcherClass fetcherWithRequest:request];
fetcher.fetchHistory = self.fetchHistory; fetcher.fetchHistory = self.fetchHistory;
fetcher.delegateQueue = self.delegateQueue;
fetcher.runLoopModes = self.runLoopModes; fetcher.runLoopModes = self.runLoopModes;
fetcher.cookieStorageMethod = self.cookieStorageMethod; fetcher.cookieStorageMethod = self.cookieStorageMethod;
fetcher.credential = self.credential; fetcher.credential = self.credential;
@@ -143,14 +146,13 @@
} }
- (BOOL)isDelayingFetcher:(GTMHTTPFetcher *)fetcher { - (BOOL)isDelayingFetcher:(GTMHTTPFetcher *)fetcher {
BOOL isDelayed;
@synchronized(self) { @synchronized(self) {
NSString *host = [[[fetcher mutableRequest] URL] host]; NSString *host = [[[fetcher mutableRequest] URL] host];
NSArray *delayedForHost = [delayedHosts_ objectForKey:host]; NSArray *delayedForHost = [delayedHosts_ objectForKey:host];
NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher];
isDelayed = (delayedForHost != nil) && (idx != NSNotFound); BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound);
return isDelayed;
} }
return isDelayed;
} }
- (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher { - (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher {
@@ -194,23 +196,32 @@
// Fetcher start and stop methods, invoked on the appropriate thread for // Fetcher start and stop methods, invoked on the appropriate thread for
// the fetcher // the fetcher
- (void)performSelector:(SEL)sel onStartThreadForFetcher:(GTMHTTPFetcher *)fetcher {
NSOperationQueue *delegateQueue = fetcher.delegateQueue;
NSThread *thread = fetcher.thread;
if (delegateQueue != nil || [thread isEqual:[NSThread currentThread]]) {
// The fetcher should run on the thread we're on now, or there's a delegate
// queue specified so it doesn't matter what thread the fetcher is started
// on, since it will call back on the queue.
[self performSelector:sel withObject:fetcher];
} else {
// Fetcher must run on a specified thread (and that thread must have a
// run loop.)
[self performSelector:sel
onThread:thread
withObject:fetcher
waitUntilDone:NO];
}
}
- (void)startFetcherOnCurrentThread:(GTMHTTPFetcher *)fetcher { - (void)startFetcherOnCurrentThread:(GTMHTTPFetcher *)fetcher {
[fetcher beginFetchMayDelay:NO [fetcher beginFetchMayDelay:NO
mayAuthorize:YES]; mayAuthorize:YES];
} }
- (void)startFetcher:(GTMHTTPFetcher *)fetcher { - (void)startFetcher:(GTMHTTPFetcher *)fetcher {
NSThread *thread = [fetcher thread]; [self performSelector:@selector(startFetcherOnCurrentThread:)
if ([thread isEqual:[NSThread currentThread]]) { onStartThreadForFetcher:fetcher];
// Same thread
[self startFetcherOnCurrentThread:fetcher];
} else {
// Different thread
[self performSelector:@selector(startFetcherOnCurrentThread:)
onThread:thread
withObject:fetcher
waitUntilDone:NO];
}
} }
- (void)stopFetcherOnCurrentThread:(GTMHTTPFetcher *)fetcher { - (void)stopFetcherOnCurrentThread:(GTMHTTPFetcher *)fetcher {
@@ -218,17 +229,8 @@
} }
- (void)stopFetcher:(GTMHTTPFetcher *)fetcher { - (void)stopFetcher:(GTMHTTPFetcher *)fetcher {
NSThread *thread = [fetcher thread]; [self performSelector:@selector(stopFetcherOnCurrentThread:)
if ([thread isEqual:[NSThread currentThread]]) { onStartThreadForFetcher:fetcher];
// Same thread
[self stopFetcherOnCurrentThread:fetcher];
} else {
// Different thread
[self performSelector:@selector(stopFetcherOnCurrentThread:)
onThread:thread
withObject:fetcher
waitUntilDone:NO];
}
} }
- (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher { - (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher {
@@ -282,47 +284,88 @@
} }
- (NSUInteger)numberOfFetchers { - (NSUInteger)numberOfFetchers {
NSUInteger running = [self numberOfRunningFetchers]; @synchronized(self) {
NSUInteger delayed = [self numberOfDelayedFetchers]; NSUInteger running = [self numberOfRunningFetchers];
return running + delayed; NSUInteger delayed = [self numberOfDelayedFetchers];
return running + delayed;
}
} }
- (NSUInteger)numberOfRunningFetchers { - (NSUInteger)numberOfRunningFetchers {
NSUInteger sum = 0; @synchronized(self) {
for (NSString *host in runningHosts_) { NSUInteger sum = 0;
NSArray *fetchers = [runningHosts_ objectForKey:host]; for (NSString *host in runningHosts_) {
sum += [fetchers count]; NSArray *fetchers = [runningHosts_ objectForKey:host];
sum += [fetchers count];
}
return sum;
} }
return sum;
} }
- (NSUInteger)numberOfDelayedFetchers { - (NSUInteger)numberOfDelayedFetchers {
NSUInteger sum = 0; @synchronized(self) {
for (NSString *host in delayedHosts_) { NSUInteger sum = 0;
NSArray *fetchers = [delayedHosts_ objectForKey:host]; for (NSString *host in delayedHosts_) {
sum += [fetchers count]; NSArray *fetchers = [delayedHosts_ objectForKey:host];
sum += [fetchers count];
}
return sum;
}
}
- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL {
@synchronized(self) {
NSMutableArray *array = nil;
NSString *host = [requestURL host];
if ([host length] == 0) return nil;
NSURL *absRequestURL = [requestURL absoluteURL];
NSArray *runningForHost = [runningHosts_ objectForKey:host];
for (GTMHTTPFetcher *fetcher in runningForHost) {
NSURL *fetcherURL = [[[fetcher mutableRequest] URL] absoluteURL];
if ([fetcherURL isEqual:absRequestURL]) {
if (array == nil) {
array = [NSMutableArray array];
}
[array addObject:fetcher];
}
}
NSArray *delayedForHost = [delayedHosts_ objectForKey:host];
for (GTMHTTPFetcher *fetcher in delayedForHost) {
NSURL *fetcherURL = [[[fetcher mutableRequest] URL] absoluteURL];
if ([fetcherURL isEqual:absRequestURL]) {
if (array == nil) {
array = [NSMutableArray array];
}
[array addObject:fetcher];
}
}
return array;
} }
return sum;
} }
- (void)stopAllFetchers { - (void)stopAllFetchers {
// Remove fetchers from the delayed list to avoid fetcherDidStop: from @synchronized(self) {
// starting more fetchers running as a side effect of stopping one // Remove fetchers from the delayed list to avoid fetcherDidStop: from
NSArray *delayedForHosts = [delayedHosts_ allValues]; // starting more fetchers running as a side effect of stopping one
[delayedHosts_ removeAllObjects]; NSArray *delayedForHosts = [delayedHosts_ allValues];
[delayedHosts_ removeAllObjects];
for (NSArray *delayedForHost in delayedForHosts) { for (NSArray *delayedForHost in delayedForHosts) {
for (GTMHTTPFetcher *fetcher in delayedForHost) { for (GTMHTTPFetcher *fetcher in delayedForHost) {
[self stopFetcher:fetcher]; [self stopFetcher:fetcher];
}
} }
}
NSArray *runningForHosts = [runningHosts_ allValues]; NSArray *runningForHosts = [runningHosts_ allValues];
[runningHosts_ removeAllObjects]; [runningHosts_ removeAllObjects];
for (NSArray *runningForHost in runningForHosts) { for (NSArray *runningForHost in runningForHosts) {
for (GTMHTTPFetcher *fetcher in runningForHost) { for (GTMHTTPFetcher *fetcher in runningForHost) {
[self stopFetcher:fetcher]; [self stopFetcher:fetcher];
}
} }
} }
} }
@@ -370,13 +413,19 @@
- (void)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { - (void)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds {
NSDate* giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; NSDate* giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds];
BOOL isMainThread = [NSThread isMainThread];
while ([self numberOfFetchers] > 0 while ([self numberOfFetchers] > 0
&& [giveUpDate timeIntervalSinceNow] > 0) { && [giveUpDate timeIntervalSinceNow] > 0) {
// Run the current run loop 1/1000 of a second to give the networking // Run the current run loop 1/1000 of a second to give the networking
// code a chance to work // code a chance to work
NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; if (isMainThread || delegateQueue_ == nil) {
[[NSRunLoop currentRunLoop] runUntilDate:stopDate]; NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001];
[[NSRunLoop currentRunLoop] runUntilDate:stopDate];
} else {
// Sleep on the delegate queue's background thread.
[NSThread sleepForTimeInterval:0.001];
}
} }
} }

View File

@@ -24,6 +24,16 @@
#import <pthread.h> #import <pthread.h>
#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
// -Wmissing-format-attribute
// when the function is anything more complex than foo(NSString *fmt, ...).
// You see the error inside the function when you turn ... into va_args and
// attempt to call another function (like vsprintf for example).
// So we just shut off the warning for this file. We reenable it at the end.
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
#endif // !__clang__
// Reference to the shared GTMLogger instance. This is not a singleton, it's // Reference to the shared GTMLogger instance. This is not a singleton, it's
// just an easy reference to one shared instance. // just an easy reference to one shared instance.
static GTMLogger *gSharedLogger = nil; static GTMLogger *gSharedLogger = nil;
@@ -265,7 +275,6 @@ static GTMLogger *gSharedLogger = nil;
@end // GTMLogger @end // GTMLogger
@implementation GTMLogger (GTMLoggerMacroHelpers) @implementation GTMLogger (GTMLoggerMacroHelpers)
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... { - (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
@@ -298,7 +307,6 @@ static GTMLogger *gSharedLogger = nil;
@end // GTMLoggerMacroHelpers @end // GTMLoggerMacroHelpers
@implementation GTMLogger (PrivateMethods) @implementation GTMLogger (PrivateMethods)
- (void)logInternalFunc:(const char *)func - (void)logInternalFunc:(const char *)func
@@ -596,3 +604,9 @@ static BOOL IsVerboseLoggingEnabled(void) {
} }
@end // GTMLogMaximumLevelFilter @end // GTMLogMaximumLevelFilter
#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
// See comment at top of file.
#pragma GCC diagnostic error "-Wmissing-format-attribute"
#endif // !__clang__

View File

@@ -47,16 +47,21 @@ static BOOL ConformsToNSObjectProtocol(Class cls) {
|| (strncmp(className, "__NS", 4) == 0) || (strncmp(className, "__NS", 4) == 0)
|| (strcmp(className, "CFObject") == 0) || (strcmp(className, "CFObject") == 0)
|| (strcmp(className, "__IncompleteProtocol") == 0) || (strcmp(className, "__IncompleteProtocol") == 0)
|| (strcmp(className, "__ARCLite__") == 0)
|| (strcmp(className, "WebMIMETypeRegistry") == 0)
#if GTM_IPHONE_SDK #if GTM_IPHONE_SDK
|| (strcmp(className, "Object") == 0) || (strcmp(className, "Object") == 0)
|| (strcmp(className, "UIKeyboardCandidateUtilities") == 0)
#endif #endif
) { ) {
return YES; return YES;
} }
// iPhone SDK does not define the |Object| class, so we instead test for the // iPhone and Mac OS X 10.8 with Obj-C 2 SDKs do not define the |Object|
// |NSObject| class. // class, so we instead test for the |NSObject| class.
#if GTM_IPHONE_SDK #if GTM_IPHONE_SDK || \
(__OBJC2__ && defined(MAC_OS_X_VERSION_10_8) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8)
// Iterate through all the protocols |cls| supports looking for NSObject. // Iterate through all the protocols |cls| supports looking for NSObject.
if (cls == [NSObject class] if (cls == [NSObject class]
|| class_conformsToProtocol(cls, @protocol(NSObject))) { || class_conformsToProtocol(cls, @protocol(NSObject))) {
@@ -78,14 +83,18 @@ void GTMMethodCheckMethodChecker(void) {
// Run through all the classes looking for class methods that are // Run through all the classes looking for class methods that are
// prefixed with xxGMMethodCheckMethod. If it finds one, it calls it. // prefixed with xxGMMethodCheckMethod. If it finds one, it calls it.
// See GTMMethodCheck.h to see what it does. // See GTMMethodCheck.h to see what it does.
#if !defined(__has_feature) || !__has_feature(objc_arc)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
#else
@autoreleasepool {
#endif
int numClasses = 0; int numClasses = 0;
int newNumClasses = objc_getClassList(NULL, 0); int newNumClasses = objc_getClassList(NULL, 0);
int i; int i;
Class *classes = NULL; Class *classes = NULL;
while (numClasses < newNumClasses) { while (numClasses < newNumClasses) {
numClasses = newNumClasses; numClasses = newNumClasses;
classes = realloc(classes, sizeof(Class) * numClasses); classes = (Class *)realloc(classes, sizeof(Class) * numClasses);
_GTMDevAssert(classes, @"Unable to allocate memory for classes"); _GTMDevAssert(classes, @"Unable to allocate memory for classes");
newNumClasses = objc_getClassList(classes, numClasses); newNumClasses = objc_getClassList(classes, numClasses);
} }
@@ -155,7 +164,11 @@ void GTMMethodCheckMethodChecker(void) {
free(methods); free(methods);
} }
free(classes); free(classes);
#if !defined(__has_feature) || !__has_feature(objc_arc)
[pool drain]; [pool drain];
#else
} // @autoreleasepool
#endif
} }
#endif // DEBUG #endif // DEBUG

View File

@@ -149,6 +149,7 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
@property (retain) NSString *scope; @property (retain) NSString *scope;
@property (retain) NSString *tokenType; @property (retain) NSString *tokenType;
@property (retain) NSString *assertion; @property (retain) NSString *assertion;
@property (retain) NSString *refreshScope;
// Apps may optionally add parameters here to be provided to the token // Apps may optionally add parameters here to be provided to the token
// endpoint on token requests and refreshes // endpoint on token requests and refreshes
@@ -176,6 +177,9 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
// with the authorizing service. // with the authorizing service.
@property (copy) NSString *serviceProvider; @property (copy) NSString *serviceProvider;
// User ID; not used for authentication
@property (retain) NSString *userID;
// User email and verified status; not used for authentication // User email and verified status; not used for authentication
// //
// The verified string can be checked with -boolValue. If the result is false, // The verified string can be checked with -boolValue. If the result is false,
@@ -184,8 +188,8 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
@property (retain) NSString *userEmail; @property (retain) NSString *userEmail;
@property (retain) NSString *userEmailIsVerified; @property (retain) NSString *userEmailIsVerified;
// Property indicating if this auth has a refresh token so is suitable for // Property indicating if this auth has a refresh or access token so is suitable
// authorizing a request. This does not guarantee that the token is valid. // for authorizing a request. This does not guarantee that the token is valid.
@property (readonly) BOOL canAuthorize; @property (readonly) BOOL canAuthorize;
// Property indicating if this object will authorize plain http request // Property indicating if this object will authorize plain http request
@@ -273,9 +277,13 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
// Check if a request appears to be authorized // Check if a request appears to be authorized
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; - (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
// Stop any pending refresh fetch // Stop any pending refresh fetch. This will also cancel the authorization
// for all fetch requests pending authorization.
- (void)stopAuthorization; - (void)stopAuthorization;
// Prevents authorization callback for a given request.
- (void)stopAuthorizationForRequest:(NSURLRequest *)request;
// OAuth fetch user-agent header value // OAuth fetch user-agent header value
- (NSString *)userAgent; - (NSString *)userAgent;

View File

@@ -31,9 +31,11 @@ static NSString *const kOAuth2TokenTypeKey = @"token_type";
static NSString *const kOAuth2ExpiresInKey = @"expires_in"; static NSString *const kOAuth2ExpiresInKey = @"expires_in";
static NSString *const kOAuth2CodeKey = @"code"; static NSString *const kOAuth2CodeKey = @"code";
static NSString *const kOAuth2AssertionKey = @"assertion"; static NSString *const kOAuth2AssertionKey = @"assertion";
static NSString *const kOAuth2RefreshScopeKey = @"refreshScope";
// additional persistent keys // additional persistent keys
static NSString *const kServiceProviderKey = @"serviceProvider"; static NSString *const kServiceProviderKey = @"serviceProvider";
static NSString *const kUserIDKey = @"userID";
static NSString *const kUserEmailKey = @"email"; static NSString *const kUserEmailKey = @"email";
static NSString *const kUserEmailIsVerifiedKey = @"isVerified"; static NSString *const kUserEmailIsVerifiedKey = @"isVerified";
@@ -44,9 +46,12 @@ static NSString *const kTokenFetchSelectorKey = @"sel";
static NSString *const kRefreshFetchArgsKey = @"requestArgs"; static NSString *const kRefreshFetchArgsKey = @"requestArgs";
// If GTMNSJSONSerialization is available, it is used for formatting JSON // If GTMNSJSONSerialization is available, it is used for formatting JSON
#if (TARGET_OS_MAC && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED < 1070)) || \
(TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED < 50000))
@interface GTMNSJSONSerialization : NSObject @interface GTMNSJSONSerialization : NSObject
+ (id)JSONObjectWithData:(NSData *)data options:(NSUInteger)opt error:(NSError **)error; + (id)JSONObjectWithData:(NSData *)data options:(NSUInteger)opt error:(NSError **)error;
@end @end
#endif
@interface GTMOAuth2ParserClass : NSObject @interface GTMOAuth2ParserClass : NSObject
// just enough of SBJSON to be able to parse // just enough of SBJSON to be able to parse
@@ -175,6 +180,7 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
refreshToken, refreshToken,
code, code,
assertion, assertion,
refreshScope,
errorString, errorString,
tokenType, tokenType,
scope, scope,
@@ -475,6 +481,29 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
} }
} }
- (void)stopAuthorizationForRequest:(NSURLRequest *)request {
@synchronized(authorizationQueue_) {
NSUInteger argIndex = 0;
BOOL found = NO;
for (GTMOAuth2AuthorizationArgs *args in authorizationQueue_) {
if ([args request] == request) {
found = YES;
break;
}
argIndex++;
}
if (found) {
[authorizationQueue_ removeObjectAtIndex:argIndex];
// If the queue is now empty, go ahead and stop the fetcher.
if ([authorizationQueue_ count] == 0) {
[self stopAuthorization];
}
}
}
}
- (BOOL)authorizeRequestImmediateArgs:(GTMOAuth2AuthorizationArgs *)args { - (BOOL)authorizeRequestImmediateArgs:(GTMOAuth2AuthorizationArgs *)args {
// This authorization entry point never attempts to refresh the access token, // This authorization entry point never attempts to refresh the access token,
// but does call the completion routine // but does call the completion routine
@@ -524,10 +553,24 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
NSThread *targetThread = args.thread; NSThread *targetThread = args.thread;
BOOL isSameThread = [targetThread isEqual:[NSThread currentThread]]; BOOL isSameThread = [targetThread isEqual:[NSThread currentThread]];
[self performSelector:@selector(invokeCallbackArgs:) if (isSameThread) {
onThread:targetThread [self invokeCallbackArgs:args];
withObject:args } else {
waitUntilDone:isSameThread]; SEL sel = @selector(invokeCallbackArgs:);
NSOperationQueue *delegateQueue = self.fetcherService.delegateQueue;
if (delegateQueue) {
NSInvocationOperation *op;
op = [[[NSInvocationOperation alloc] initWithTarget:self
selector:sel
object:args] autorelease];
[delegateQueue addOperation:op];
} else {
[self performSelector:sel
onThread:targetThread
withObject:args
waitUntilDone:NO];
}
}
} }
BOOL didAuth = (args.error == nil); BOOL didAuth = (args.error == nil);
@@ -591,13 +634,15 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
NSString *accessToken = self.accessToken; NSString *accessToken = self.accessToken;
NSString *refreshToken = self.refreshToken; NSString *refreshToken = self.refreshToken;
NSString *assertion = self.assertion; NSString *assertion = self.assertion;
NSString *code = self.code;
BOOL hasRefreshToken = ([refreshToken length] > 0); BOOL hasRefreshToken = ([refreshToken length] > 0);
BOOL hasAccessToken = ([accessToken length] > 0); BOOL hasAccessToken = ([accessToken length] > 0);
BOOL hasAssertion = ([assertion length] > 0); BOOL hasAssertion = ([assertion length] > 0);
BOOL hasCode = ([code length] > 0);
// Determine if we need to refresh the access token // Determine if we need to refresh the access token
if (hasRefreshToken || hasAssertion) { if (hasRefreshToken || hasAssertion || hasCode) {
if (!hasAccessToken) { if (!hasAccessToken) {
shouldRefresh = YES; shouldRefresh = YES;
} else { } else {
@@ -649,7 +694,6 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
NSMutableDictionary *paramsDict = [NSMutableDictionary dictionary]; NSMutableDictionary *paramsDict = [NSMutableDictionary dictionary];
NSString *commentTemplate;
NSString *fetchType; NSString *fetchType;
NSString *refreshToken = self.refreshToken; NSString *refreshToken = self.refreshToken;
@@ -660,14 +704,18 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
// We have a refresh token // We have a refresh token
[paramsDict setObject:@"refresh_token" forKey:@"grant_type"]; [paramsDict setObject:@"refresh_token" forKey:@"grant_type"];
[paramsDict setObject:refreshToken forKey:@"refresh_token"]; [paramsDict setObject:refreshToken forKey:@"refresh_token"];
NSString *refreshScope = self.refreshScope;
if ([refreshScope length] > 0) {
[paramsDict setObject:refreshScope forKey:@"scope"];
}
fetchType = kGTMOAuth2FetchTypeRefresh; fetchType = kGTMOAuth2FetchTypeRefresh;
commentTemplate = @"refresh token for %@";
} else if (code) { } else if (code) {
// We have a code string // We have a code string
[paramsDict setObject:@"authorization_code" forKey:@"grant_type"]; [paramsDict setObject:@"authorization_code" forKey:@"grant_type"];
[paramsDict setObject:code forKey:@"code"]; [paramsDict setObject:code forKey:@"code"];
NSString *redirectURI = self.redirectURI; NSString *redirectURI = self.redirectURI;
if ([redirectURI length] > 0) { if ([redirectURI length] > 0) {
[paramsDict setObject:redirectURI forKey:@"redirect_uri"]; [paramsDict setObject:redirectURI forKey:@"redirect_uri"];
@@ -679,13 +727,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
} }
fetchType = kGTMOAuth2FetchTypeToken; fetchType = kGTMOAuth2FetchTypeToken;
commentTemplate = @"fetch tokens for %@";
} else if (assertion) { } else if (assertion) {
// We have an assertion string // We have an assertion string
[paramsDict setObject:assertion forKey:@"assertion"]; [paramsDict setObject:assertion forKey:@"assertion"];
[paramsDict setObject:@"http://oauth.net/grant_type/jwt/1.0/bearer" [paramsDict setObject:@"http://oauth.net/grant_type/jwt/1.0/bearer"
forKey:@"grant_type"]; forKey:@"grant_type"];
commentTemplate = @"fetch tokens for %@";
fetchType = kGTMOAuth2FetchTypeAssertion; fetchType = kGTMOAuth2FetchTypeAssertion;
} else { } else {
#if DEBUG #if DEBUG
@@ -732,7 +778,8 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
fetcher = [GTMHTTPFetcher fetcherWithRequest:request]; fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
} }
[fetcher setCommentWithFormat:commentTemplate, [tokenURL host]]; NSString *const template = (refreshToken ? @"refresh token for %@" : @"fetch tokens for %@");
[fetcher setCommentWithFormat:template, [tokenURL host]];
fetcher.postData = paramData; fetcher.postData = paramData;
fetcher.retryEnabled = YES; fetcher.retryEnabled = YES;
fetcher.maxRetryInterval = 15.0; fetcher.maxRetryInterval = 15.0;
@@ -881,6 +928,7 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
[dict setValue:refreshToken forKey:kOAuth2RefreshTokenKey]; [dict setValue:refreshToken forKey:kOAuth2RefreshTokenKey];
[dict setValue:accessToken forKey:kOAuth2AccessTokenKey]; [dict setValue:accessToken forKey:kOAuth2AccessTokenKey];
[dict setValue:self.serviceProvider forKey:kServiceProviderKey]; [dict setValue:self.serviceProvider forKey:kServiceProviderKey];
[dict setValue:self.userID forKey:kUserIDKey];
[dict setValue:self.userEmail forKey:kUserEmailKey]; [dict setValue:self.userEmail forKey:kUserEmailKey];
[dict setValue:self.userEmailIsVerified forKey:kUserEmailIsVerifiedKey]; [dict setValue:self.userEmailIsVerified forKey:kUserEmailIsVerifiedKey];
[dict setValue:self.scope forKey:kOAuth2ScopeKey]; [dict setValue:self.scope forKey:kOAuth2ScopeKey];
@@ -948,6 +996,14 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
[self.parameters setValue:str forKey:kOAuth2AssertionKey]; [self.parameters setValue:str forKey:kOAuth2AssertionKey];
} }
- (NSString *)refreshScope {
return [self.parameters objectForKey:kOAuth2RefreshScopeKey];
}
- (void)setRefreshScope:(NSString *)str {
[self.parameters setValue:str forKey:kOAuth2RefreshScopeKey];
}
- (NSString *)errorString { - (NSString *)errorString {
return [self.parameters objectForKey:kOAuth2ErrorKey]; return [self.parameters objectForKey:kOAuth2ErrorKey];
} }
@@ -1007,6 +1063,14 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
[self.parameters setValue:str forKey:kServiceProviderKey]; [self.parameters setValue:str forKey:kServiceProviderKey];
} }
- (NSString *)userID {
return [self.parameters objectForKey:kUserIDKey];
}
- (void)setUserID:(NSString *)str {
[self.parameters setValue:str forKey:kUserIDKey];
}
- (NSString *)userEmail { - (NSString *)userEmail {
return [self.parameters objectForKey:kUserEmailKey]; return [self.parameters objectForKey:kUserEmailKey];
} }

View File

@@ -152,11 +152,24 @@
// delegate's finishedSelector // delegate's finishedSelector
- (void)windowWasClosed; - (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 - #pragma mark -
// Revocation of an authorized token from Google
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
// Revocation of an authorized token from Google
+ (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth; + (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 #endif
#pragma mark - #pragma mark -

View File

@@ -46,12 +46,11 @@ NSString *const kOOBString = @"urn:ietf:wg:oauth:2.0:oob";
+ (NSMutableURLRequest *)mutableURLRequestWithURL:(NSURL *)oldURL + (NSMutableURLRequest *)mutableURLRequestWithURL:(NSURL *)oldURL
paramString:(NSString *)paramStr; paramString:(NSString *)paramStr;
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
- (void)addScopeForGoogleUserInfo;
- (void)fetchGoogleUserInfo; - (void)fetchGoogleUserInfo;
#endif #endif
- (void)finishSignInWithError:(NSError *)error; - (void)finishSignInWithError:(NSError *)error;
- (void)handleCallbackReached;
- (void)auth:(GTMOAuth2Authentication *)auth - (void)auth:(GTMOAuth2Authentication *)auth
finishedWithFetcher:(GTMHTTPFetcher *)fetcher finishedWithFetcher:(GTMHTTPFetcher *)fetcher
error:(NSError *)error; error:(NSError *)error;
@@ -136,6 +135,27 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
return auth; 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 #endif
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth - (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
@@ -217,24 +237,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
// For signing in to Google, append the scope for obtaining the authenticated // For signing in to Google, append the scope for obtaining the authenticated
// user email and profile, as appropriate // user email and profile, as appropriate
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
GTMOAuth2Authentication *auth = self.authentication; [self addScopeForGoogleUserInfo];
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 #endif
// start the authorization // start the authorization
@@ -350,7 +353,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
// requested // requested
// //
// When the request is for the callback URL, this method invokes // When the request is for the callback URL, this method invokes
// handleCallbackReached and returns YES // authCodeObtained and returns YES
- (BOOL)requestRedirectedToRequest:(NSURLRequest *)redirectedRequest { - (BOOL)requestRedirectedToRequest:(NSURLRequest *)redirectedRequest {
// for Google's installed app sign-in protocol, we'll look for the // for Google's installed app sign-in protocol, we'll look for the
// end-of-sign-in indicator in the titleChanged: method below // end-of-sign-in indicator in the titleChanged: method below
@@ -400,7 +403,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
@"response lacks auth code or error"); @"response lacks auth code or error");
#endif #endif
[self handleCallbackReached]; [self authCodeObtained];
} }
// tell the delegate that we did handle this request // tell the delegate that we did handle this request
return YES; return YES;
@@ -410,7 +413,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
// been loadded // been loadded
// //
// When the title indicates sign-in has completed, this method invokes // When the title indicates sign-in has completed, this method invokes
// handleCallbackReached and returns YES // authCodeObtained and returns YES
- (BOOL)titleChanged:(NSString *)title { - (BOOL)titleChanged:(NSString *)title {
// return YES if the OAuth flow ending title was detected // return YES if the OAuth flow ending title was detected
@@ -432,7 +435,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
if (!self.hasHandledCallback) { if (!self.hasHandledCallback) {
[self.authentication setKeysForResponseDictionary:dict]; [self.authentication setKeysForResponseDictionary:dict];
[self handleCallbackReached]; [self authCodeObtained];
} }
return YES; return YES;
} }
@@ -467,7 +470,7 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
return NO; return NO;
} }
- (void)handleCallbackReached { - (void)authCodeObtained {
// the callback page was requested, or the authenticate code was loaded // 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 // into a page's title, so exchange the auth code for access & refresh tokens
// and tell the window to close // and tell the window to close
@@ -475,7 +478,19 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
// avoid duplicate signals that the callback point has been reached // avoid duplicate signals that the callback point has been reached
self.hasHandledCallback = YES; self.hasHandledCallback = YES;
[self closeTheWindow]; // 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; NSError *error = nil;
@@ -539,22 +554,15 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
} }
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
- (void)fetchGoogleUserInfo { + (GTMHTTPFetcher *)userInfoFetcherWithAuth:(GTMOAuth2Authentication *)auth {
// fetch the user's email address // create a fetcher for obtaining the user's email or profile
NSURL *infoURL = [[self class] googleUserInfoURL]; NSURL *infoURL = [[self class] googleUserInfoURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:infoURL]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:infoURL];
GTMOAuth2Authentication *auth = self.authentication;
NSString *userAgent = [auth userAgent]; NSString *userAgent = [auth userAgent];
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; [request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
[request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"]; [request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];
// we can do a synchronous authorization since this method is called
// only immediately after a fresh access token has been obtained
[auth authorizeRequest:request];
GTMHTTPFetcher *fetcher; GTMHTTPFetcher *fetcher;
id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService; id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService;
if (fetcherService) { if (fetcherService) {
@@ -562,10 +570,17 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
} else { } else {
fetcher = [GTMHTTPFetcher fetcherWithRequest:request]; fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
} }
fetcher.authorizer = auth;
fetcher.retryEnabled = YES; fetcher.retryEnabled = YES;
fetcher.maxRetryInterval = 15.0; fetcher.maxRetryInterval = 15.0;
fetcher.comment = @"user info"; fetcher.comment = @"user info";
return fetcher;
}
- (void)fetchGoogleUserInfo {
// fetch the user's email address or profile
GTMOAuth2Authentication *auth = self.authentication;
GTMHTTPFetcher *fetcher = [[self class] userInfoFetcherWithAuth:auth];
[fetcher beginFetchWithDelegate:self [fetcher beginFetchWithDelegate:self
didFinishSelector:@selector(infoFetcher:finishedWithData:error:)]; didFinishSelector:@selector(infoFetcher:finishedWithData:error:)];
@@ -601,6 +616,10 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
if (profileDict) { if (profileDict) {
self.userProfile = profileDict; self.userProfile = profileDict;
// Save the ID into the auth object
NSString *identifier = [profileDict objectForKey:@"id"];
[auth setUserID:identifier];
// Save the email into the auth object // Save the email into the auth object
NSString *email = [profileDict objectForKey:@"email"]; NSString *email = [profileDict objectForKey:@"email"];
[auth setUserEmail:email]; [auth setUserEmail:email];
@@ -757,7 +776,8 @@ static void ReachabilityCallBack(SCNetworkReachabilityRef target,
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
+ (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth { + (void)revokeTokenForGoogleAuthentication:(GTMOAuth2Authentication *)auth {
if (auth.canAuthorize if (auth.refreshToken != nil
&& auth.canAuthorize
&& [auth.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) { && [auth.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) {
// create a signed revocation request for this authentication object // create a signed revocation request for this authentication object
@@ -767,44 +787,45 @@ static void ReachabilityCallBack(SCNetworkReachabilityRef target,
NSString *token = auth.refreshToken; NSString *token = auth.refreshToken;
NSString *encoded = [GTMOAuth2Authentication encodedOAuthValueForString:token]; NSString *encoded = [GTMOAuth2Authentication encodedOAuthValueForString:token];
NSString *body = [@"token=" stringByAppendingString:encoded]; if (encoded != nil) {
NSString *body = [@"token=" stringByAppendingString:encoded];
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]]; [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:@"POST"]; [request setHTTPMethod:@"POST"];
NSString *userAgent = [auth userAgent]; NSString *userAgent = [auth userAgent];
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; [request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
// there's nothing to be done if revocation succeeds or fails // there's nothing to be done if revocation succeeds or fails
GTMHTTPFetcher *fetcher; GTMHTTPFetcher *fetcher;
id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService; id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService;
if (fetcherService) { if (fetcherService) {
fetcher = [fetcherService fetcherWithRequest:request]; fetcher = [fetcherService fetcherWithRequest:request];
} else { } else {
fetcher = [GTMHTTPFetcher fetcherWithRequest:request]; fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
} }
fetcher.comment = @"revoke token"; fetcher.comment = @"revoke token";
// Use a completion handler fetch for better debugging, but only if we're // Use a completion handler fetch for better debugging, but only if we're
// guaranteed that blocks are available in the runtime // guaranteed that blocks are available in the runtime
#if (!TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)) || \ #if (!TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)) || \
(TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)) (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000))
// Blocks are available // Blocks are available
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
#if DEBUG #if DEBUG
if (error) { if (error) {
NSString *errStr = [[[NSString alloc] initWithData:data NSString *errStr = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease]; encoding:NSUTF8StringEncoding] autorelease];
NSLog(@"revoke error: %@", errStr); NSLog(@"revoke error: %@", errStr);
} }
#endif // DEBUG #endif // DEBUG
}]; }];
#else #else
// Blocks may not be available // Blocks may not be available
[fetcher beginFetchWithDelegate:nil didFinishSelector:NULL]; [fetcher beginFetchWithDelegate:nil didFinishSelector:NULL];
#endif #endif
}
} }
[auth reset]; [auth reset];
} }
#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT

View File

@@ -53,6 +53,7 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
@private @private
UIButton *backButton_; UIButton *backButton_;
UIButton *forwardButton_; UIButton *forwardButton_;
UIActivityIndicatorView *initialActivityIndicator_;
UIView *navButtonsView_; UIView *navButtonsView_;
UIBarButtonItem *rightBarButtonItem_; UIBarButtonItem *rightBarButtonItem_;
UIWebView *webView_; UIWebView *webView_;
@@ -73,6 +74,8 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
#if NS_BLOCKS_AVAILABLE #if NS_BLOCKS_AVAILABLE
void (^completionBlock_)(GTMOAuth2ViewControllerTouch *, GTMOAuth2Authentication *, NSError *); void (^completionBlock_)(GTMOAuth2ViewControllerTouch *, GTMOAuth2Authentication *, NSError *);
void (^popViewBlock_)(void);
#endif #endif
NSString *keychainItemName_; NSString *keychainItemName_;
@@ -82,6 +85,10 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
// of the web view // of the web view
NSString *initialHTMLString_; 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 // if non-nil, the URL for which cookies will be deleted when the
// browser view is dismissed // browser view is dismissed
NSURL *browserCookiesURL_; NSURL *browserCookiesURL_;
@@ -89,10 +96,12 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
id userData_; id userData_;
NSMutableDictionary *properties_; NSMutableDictionary *properties_;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
// We delegate the decision to our owning NavigationController (if any). // We delegate the decision to our owning NavigationController (if any).
// But, the NavigationController will call us back, and ask us. // But, the NavigationController will call us back, and ask us.
// BOOL keeps us from infinite looping. // BOOL keeps us from infinite looping.
BOOL isInsideShouldAutorotateToInterfaceOrientation_; BOOL isInsideShouldAutorotateToInterfaceOrientation_;
#endif
// YES, when view first shown in this signIn session. // YES, when view first shown in this signIn session.
BOOL isViewShown_; BOOL isViewShown_;
@@ -132,6 +141,11 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
// initial view color // initial view color
@property (nonatomic, copy) NSString *initialHTMLString; @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 // the underlying object to hold authentication tokens and authorize http
// requests // requests
@property (nonatomic, retain, readonly) GTMOAuth2Authentication *authentication; @property (nonatomic, retain, readonly) GTMOAuth2Authentication *authentication;
@@ -142,10 +156,17 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
// user interface elements // user interface elements
@property (nonatomic, retain) IBOutlet UIButton *backButton; @property (nonatomic, retain) IBOutlet UIButton *backButton;
@property (nonatomic, retain) IBOutlet UIButton *forwardButton; @property (nonatomic, retain) IBOutlet UIButton *forwardButton;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *initialActivityIndicator;
@property (nonatomic, retain) IBOutlet UIView *navButtonsView; @property (nonatomic, retain) IBOutlet UIView *navButtonsView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *rightBarButtonItem; @property (nonatomic, retain) IBOutlet UIBarButtonItem *rightBarButtonItem;
@property (nonatomic, retain) IBOutlet UIWebView *webView; @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 // the default timeout for an unreachable network during display of the
// sign-in page is 10 seconds; set this to 0 to have no timeout // sign-in page is 10 seconds; set this to 0 to have no timeout
@property (nonatomic, assign) NSTimeInterval networkLossTimeoutInterval; @property (nonatomic, assign) NSTimeInterval networkLossTimeoutInterval;
@@ -244,10 +265,6 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler; completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler;
#endif #endif
// Override default in UIViewController. If we have a navigationController, ask
// it. else default result (i.e., Portrait mode only).
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
// subclasses may override authNibName to specify a custom name // subclasses may override authNibName to specify a custom name
+ (NSString *)authNibName; + (NSString *)authNibName;

View File

@@ -55,7 +55,8 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
forwardButton = forwardButton_, forwardButton = forwardButton_,
navButtonsView = navButtonsView_, navButtonsView = navButtonsView_,
rightBarButtonItem = rightBarButtonItem_, rightBarButtonItem = rightBarButtonItem_,
webView = webView_; webView = webView_,
initialActivityIndicator = initialActivityIndicator_;
@synthesize keychainItemName = keychainItemName_, @synthesize keychainItemName = keychainItemName_,
keychainItemAccessibility = keychainItemAccessibility_, keychainItemAccessibility = keychainItemAccessibility_,
@@ -65,6 +66,10 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
userData = userData_, userData = userData_,
properties = properties_; properties = properties_;
#if NS_BLOCKS_AVAILABLE
@synthesize popViewBlock = popViewBlock_;
#endif
#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT #if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
+ (id)controllerWithScope:(NSString *)scope + (id)controllerWithScope:(NSString *)scope
clientID:(NSString *)clientID clientID:(NSString *)clientID
@@ -153,7 +158,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
authorizationURL:authorizationURL authorizationURL:authorizationURL
keychainItemName:keychainItemName keychainItemName:keychainItemName
delegate:delegate delegate:delegate
finishedSelector:finishedSelector] autorelease]; finishedSelector:finishedSelector] autorelease];
} }
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth - (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
@@ -178,7 +183,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
delegate:self delegate:self
webRequestSelector:@selector(signIn:displayRequest:) webRequestSelector:@selector(signIn:displayRequest:)
finishedSelector:@selector(signIn:finishedWithAuth:error:)]; finishedSelector:@selector(signIn:finishedWithAuth:error:)];
// if the user is signing in to a Google service, we'll delete the // if the user is signing in to a Google service, we'll delete the
// Google authentication browser cookies upon completion // Google authentication browser cookies upon completion
// //
@@ -230,6 +235,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
[backButton_ release]; [backButton_ release];
[forwardButton_ release]; [forwardButton_ release];
[initialActivityIndicator_ release];
[navButtonsView_ release]; [navButtonsView_ release];
[rightBarButtonItem_ release]; [rightBarButtonItem_ release];
[webView_ release]; [webView_ release];
@@ -238,6 +244,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
[delegate_ release]; [delegate_ release];
#if NS_BLOCKS_AVAILABLE #if NS_BLOCKS_AVAILABLE
[completionBlock_ release]; [completionBlock_ release];
[popViewBlock_ release];
#endif #endif
[keychainItemName_ release]; [keychainItemName_ release];
[initialHTMLString_ release]; [initialHTMLString_ release];
@@ -358,26 +365,32 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
- (void)viewDidLoad { - (void)viewDidLoad {
// the app may prefer some html other than blank white to be displayed
// before the sign-in web page loads
NSString *html = self.initialHTMLString;
if ([html length] > 0) {
[[self webView] loadHTMLString:html baseURL:nil];
}
rightBarButtonItem_.customView = navButtonsView_; rightBarButtonItem_.customView = navButtonsView_;
self.navigationItem.rightBarButtonItem = rightBarButtonItem_; self.navigationItem.rightBarButtonItem = rightBarButtonItem_;
} }
- (void)popView { - (void)popView {
if (self.navigationController.topViewController == self) { #if NS_BLOCKS_AVAILABLE
if (!self.view.isHidden) { void (^popViewBlock)() = self.popViewBlock;
#else
id popViewBlock = nil;
#endif
if (popViewBlock || self.navigationController.topViewController == self) {
if (!self.view.hidden) {
// Set the flag to our viewWillDisappear method so it knows // Set the flag to our viewWillDisappear method so it knows
// this is a disappearance initiated by the sign-in object, // this is a disappearance initiated by the sign-in object,
// not the user cancelling via the navigation controller // not the user cancelling via the navigation controller
didDismissSelf_ = YES; didDismissSelf_ = YES;
[self.navigationController popViewControllerAnimated:YES]; if (popViewBlock) {
#if NS_BLOCKS_AVAILABLE
popViewBlock();
self.popViewBlock = nil;
#endif
} else {
[self.navigationController popViewControllerAnimated:YES];
}
self.view.hidden = YES; self.view.hidden = YES;
} }
} }
@@ -488,6 +501,14 @@ static Class gSignInClass = Nil;
return ([name length] > 0); return ([name length] > 0);
} }
- (BOOL)showsInitialActivityIndicator {
return (mustShowActivityIndicator_ == 1 || initialHTMLString_ == nil);
}
- (void)setShowsInitialActivityIndicator:(BOOL)flag {
mustShowActivityIndicator_ = (flag ? 1 : -1);
}
#pragma mark User Properties #pragma mark User Properties
- (void)setProperty:(id)obj forKey:(NSString *)key { - (void)setProperty:(id)obj forKey:(NSString *)key {
@@ -514,8 +535,9 @@ static Class gSignInClass = Nil;
#pragma mark SignIn callbacks #pragma mark SignIn callbacks
- (void)signIn:(GTMOAuth2SignIn *)signIn displayRequest:(NSURLRequest *)request { - (void)signIn:(GTMOAuth2SignIn *)signIn displayRequest:(NSURLRequest *)request {
// this is the signIn object's webRequest method, telling the controller // This is the signIn object's webRequest method, telling the controller
// to either display the request in the webview, or close the window // to either display the request in the webview, or if the request is nil,
// to close the window.
// //
// All web requests and all window closing goes through this routine // All web requests and all window closing goes through this routine
@@ -535,12 +557,24 @@ static Class gSignInClass = Nil;
if (isDateValid) { if (isDateValid) {
// Display the request. // Display the request.
self.request = request; self.request = request;
BOOL shouldWaitForHTML = ([self.initialHTMLString length] > 0); // The app may prefer some html other than blank white to be displayed
if (shouldWaitForHTML) { // before the sign-in web page loads.
[self.webView performSelector:@selector(loadRequest:) // The first fetch might be slow, so the client programmer may want
withObject:request // to show a local "loading" message.
afterDelay:0.05]; // On iOS 5+, UIWebView will ignore loadHTMLString: if it's followed by
// a loadRequest: call, so if there is a "loading" message we defer
// the loadRequest: until after after we've drawn the "loading" message.
//
// If there is no initial html string, we show the activity indicator
// unless the user set showsInitialActivityIndicator to NO; if there
// is an initial html string, we hide the indicator unless the user set
// showsInitialActivityIndicator to YES.
NSString *html = self.initialHTMLString;
if ([html length] > 0) {
[initialActivityIndicator_ setHidden:(mustShowActivityIndicator_ < 1)];
[self.webView loadHTMLString:html baseURL:nil];
} else { } else {
[initialActivityIndicator_ setHidden:(mustShowActivityIndicator_ < 0)];
[self.webView loadRequest:request]; [self.webView loadRequest:request];
} }
} else { } else {
@@ -552,7 +586,7 @@ static Class gSignInClass = Nil;
// //
// Even better is for apps to check the system clock and show some more // Even better is for apps to check the system clock and show some more
// helpful, localized instructions for users; this is really a fallback. // helpful, localized instructions for users; this is really a fallback.
NSString *html = @"<html><body><div align=center><font size='7'>" NSString *const html = @"<html><body><div align=center><font size='7'>"
@"&#x231A; ?<br><i>System Clock Incorrect</i><br>%@" @"&#x231A; ?<br><i>System Clock Incorrect</i><br>%@"
@"</font></div></body></html>"; @"</font></div></body></html>";
NSString *errHTML = [NSString stringWithFormat:html, [NSDate date]]; NSString *errHTML = [NSString stringWithFormat:html, [NSDate date]];
@@ -673,6 +707,10 @@ static Class gSignInClass = Nil;
// this will indirectly call our signIn:finishedWithAuth:error: method // this will indirectly call our signIn:finishedWithAuth:error: method
// for us // for us
[signIn_ windowWasClosed]; [signIn_ windowWasClosed];
#if NS_BLOCKS_AVAILABLE
self.popViewBlock = nil;
#endif
} }
// prevent the next sign-in from showing in the WebView that the user is // prevent the next sign-in from showing in the WebView that the user is
@@ -682,6 +720,13 @@ static Class gSignInClass = Nil;
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
} }
- (void)viewDidLayoutSubviews {
// We don't call super's version of this method because
// -[UIViewController viewDidLayoutSubviews] is documented as a no-op, that
// didn't exist before iOS 5.
[initialActivityIndicator_ setCenter:[webView_ center]];
}
- (BOOL)webView:(UIWebView *)webView - (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType { navigationType:(UIWebViewNavigationType)navigationType {
@@ -724,9 +769,16 @@ static Class gSignInClass = Nil;
#endif #endif
} }
[signIn_ cookiesChanged:[NSHTTPCookieStorage sharedHTTPCookieStorage]]; if (self.request && [self.initialHTMLString length] > 0) {
// The request was pending.
[self setInitialHTMLString:nil];
[self.webView loadRequest:self.request];
} else {
[initialActivityIndicator_ setHidden:YES];
[signIn_ cookiesChanged:[NSHTTPCookieStorage sharedHTTPCookieStorage]];
[self updateUI]; [self updateUI];
}
} }
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
@@ -762,6 +814,17 @@ static Class gSignInClass = Nil;
} }
} }
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
// When running on a device with an OS version < 6, this gets called.
//
// Since it is never called in iOS 6 or greater, if your min deployment
// target is iOS6 or greater, then you don't need to have this method compiled
// into your app.
//
// When running on a device with an OS version 6 or greater, this code is
// not called. - (NSUInteger)supportedInterfaceOrientations; would be called,
// if it existed. Since it is absent,
// Allow the default orientations: All for iPad, all but upside down for iPhone.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
BOOL value = YES; BOOL value = YES;
if (!isInsideShouldAutorotateToInterfaceOrientation_) { if (!isInsideShouldAutorotateToInterfaceOrientation_) {
@@ -776,6 +839,8 @@ static Class gSignInClass = Nil;
} }
return value; return value;
} }
#endif
@end @end

View File

@@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10"> <archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
<data> <data>
<int key="IBDocument.SystemTarget">768</int> <int key="IBDocument.SystemTarget">1024</int>
<string key="IBDocument.SystemVersion">10J869</string> <string key="IBDocument.SystemVersion">12C60</string>
<string key="IBDocument.InterfaceBuilderVersion">851</string> <string key="IBDocument.InterfaceBuilderVersion">2840</string>
<string key="IBDocument.AppKitVersion">1038.35</string> <string key="IBDocument.AppKitVersion">1187.34</string>
<string key="IBDocument.HIToolboxVersion">461.00</string> <string key="IBDocument.HIToolboxVersion">625.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions"> <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="NS.object.0">141</string> <string key="NS.object.0">1926</string>
</object> </object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<integer value="4"/> <string>IBProxyObject</string>
<integer value="15"/> <string>IBUIActivityIndicatorView</string>
<string>IBUIBarButtonItem</string>
<string>IBUIButton</string>
<string>IBUINavigationItem</string>
<string>IBUIView</string>
<string>IBUIWebView</string>
</object> </object>
<object class="NSArray" key="IBDocument.PluginDependencies"> <object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object> </object>
<object class="NSMutableDictionary" key="IBDocument.Metadata"> <object class="NSMutableDictionary" key="IBDocument.Metadata">
<bool key="EncodedWithXMLCoder">YES</bool> <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
<object class="NSArray" key="dict.sortedKeys" id="0"> <integer value="1" key="NS.object.0"/>
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object> </object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
@@ -56,16 +56,13 @@
<int key="NSvFlags">292</int> <int key="NSvFlags">292</int>
<string key="NSFrameSize">{30, 30}</string> <string key="NSFrameSize">{30, 30}</string>
<reference key="NSSuperview" ref="808907889"/> <reference key="NSSuperview" ref="808907889"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="981703116"/>
<bool key="IBUIOpaque">NO</bool> <bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool> <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int> <int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int> <int key="IBUIContentVerticalAlignment">0</int>
<object class="NSFont" key="IBUIFont" id="530402572">
<string key="NSName">Helvetica-Bold</string>
<double key="NSSize">24</double>
<int key="NSfFlags">16</int>
</object>
<string key="IBUITitleShadowOffset">{0, -2}</string> <string key="IBUITitleShadowOffset">{0, -2}</string>
<string key="IBUINormalTitle">◀</string> <string key="IBUINormalTitle">◀</string>
<object class="NSColor" key="IBUIHighlightedTitleColor" id="193465259"> <object class="NSColor" key="IBUIHighlightedTitleColor" id="193465259">
@@ -81,18 +78,30 @@
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC41AA</bytes> <bytes key="NSWhite">MC41AA</bytes>
</object> </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>
<object class="IBUIButton" id="981703116"> <object class="IBUIButton" id="981703116">
<reference key="NSNextResponder" ref="808907889"/> <reference key="NSNextResponder" ref="808907889"/>
<int key="NSvFlags">292</int> <int key="NSvFlags">292</int>
<string key="NSFrame">{{30, 0}, {30, 30}}</string> <string key="NSFrame">{{30, 0}, {30, 30}}</string>
<reference key="NSSuperview" ref="808907889"/> <reference key="NSSuperview" ref="808907889"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<bool key="IBUIOpaque">NO</bool> <bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool> <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int> <int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int> <int key="IBUIContentVerticalAlignment">0</int>
<reference key="IBUIFont" ref="530402572"/>
<string key="IBUITitleShadowOffset">{0, -2}</string> <string key="IBUITitleShadowOffset">{0, -2}</string>
<string key="IBUINormalTitle">▶</string> <string key="IBUINormalTitle">▶</string>
<reference key="IBUIHighlightedTitleColor" ref="193465259"/> <reference key="IBUIHighlightedTitleColor" ref="193465259"/>
@@ -102,10 +111,14 @@
</object> </object>
<reference key="IBUINormalTitleColor" ref="193465259"/> <reference key="IBUINormalTitleColor" ref="193465259"/>
<reference key="IBUINormalTitleShadowColor" ref="999379443"/> <reference key="IBUINormalTitleShadowColor" ref="999379443"/>
<reference key="IBUIFontDescription" ref="621440819"/>
<reference key="IBUIFont" ref="530402572"/>
</object> </object>
</object> </object>
<string key="NSFrameSize">{60, 30}</string> <string key="NSFrameSize">{60, 30}</string>
<reference key="NSSuperview"/> <reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="453250804"/>
<object class="NSColor" key="IBUIBackgroundColor"> <object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
<bytes key="NSWhite">MSAwAA</bytes> <bytes key="NSWhite">MSAwAA</bytes>
@@ -113,6 +126,7 @@
<bool key="IBUIOpaque">NO</bool> <bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool> <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics"> <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
<int key="IBUIInterfaceOrientation">3</int>
<int key="interfaceOrientation">3</int> <int key="interfaceOrientation">3</int>
</object> </object>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
@@ -127,6 +141,8 @@
<int key="NSvFlags">274</int> <int key="NSvFlags">274</int>
<string key="NSFrameSize">{320, 460}</string> <string key="NSFrameSize">{320, 460}</string>
<reference key="NSSuperview" ref="426018584"/> <reference key="NSSuperview" ref="426018584"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="268967673"/>
<object class="NSColor" key="IBUIBackgroundColor"> <object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int> <int key="NSColorSpace">1</int>
<bytes key="NSRGB">MSAxIDEAA</bytes> <bytes key="NSRGB">MSAxIDEAA</bytes>
@@ -137,9 +153,25 @@
<int key="IBUIDataDetectorTypes">1</int> <int key="IBUIDataDetectorTypes">1</int>
<bool key="IBUIDetectsPhoneNumbers">YES</bool> <bool key="IBUIDetectsPhoneNumbers">YES</bool>
</object> </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> </object>
<string key="NSFrameSize">{320, 460}</string> <string key="NSFrameSize">{320, 460}</string>
<reference key="NSSuperview"/> <reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="663477729"/>
<object class="NSColor" key="IBUIBackgroundColor"> <object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes> <bytes key="NSWhite">MQA</bytes>
@@ -153,40 +185,6 @@
<object class="IBObjectContainer" key="IBDocument.Objects"> <object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords"> <object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<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 class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection"> <object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">rightBarButtonItem</string> <string key="label">rightBarButtonItem</string>
@@ -235,13 +233,57 @@
</object> </object>
<int key="connectionID">29</int> <int key="connectionID">29</int>
</object> </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>
<object class="IBMutableOrderedSet" key="objectRecords"> <object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects"> <object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">0</int> <int key="objectID">0</int>
<reference key="object" ref="0"/> <object class="NSArray" key="object" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1000"/> <reference key="children" ref="1000"/>
<nil key="parent"/> <nil key="parent"/>
</object> </object>
@@ -295,6 +337,7 @@
<object class="NSMutableArray" key="children"> <object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="663477729"/> <reference ref="663477729"/>
<reference ref="268967673"/>
</object> </object>
<reference key="parent" ref="0"/> <reference key="parent" ref="0"/>
</object> </object>
@@ -303,6 +346,11 @@
<reference key="object" ref="663477729"/> <reference key="object" ref="663477729"/>
<reference key="parent" ref="426018584"/> <reference key="parent" ref="426018584"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">31</int>
<reference key="object" ref="268967673"/>
<reference key="parent" ref="426018584"/>
</object>
</object> </object>
</object> </object>
<object class="NSMutableDictionary" key="flattenedProperties"> <object class="NSMutableDictionary" key="flattenedProperties">
@@ -310,27 +358,29 @@
<object class="NSArray" key="dict.sortedKeys"> <object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.CustomClassName</string> <string>-1.CustomClassName</string>
<string>-1.IBPluginDependency</string>
<string>-2.CustomClassName</string> <string>-2.CustomClassName</string>
<string>-2.IBPluginDependency</string>
<string>10.IBPluginDependency</string> <string>10.IBPluginDependency</string>
<string>15.IBEditorWindowLastContentRect</string>
<string>15.IBPluginDependency</string> <string>15.IBPluginDependency</string>
<string>16.IBPluginDependency</string> <string>16.IBPluginDependency</string>
<string>17.IBPluginDependency</string> <string>17.IBPluginDependency</string>
<string>27.IBEditorWindowLastContentRect</string>
<string>27.IBPluginDependency</string> <string>27.IBPluginDependency</string>
<string>31.IBPluginDependency</string>
<string>4.IBPluginDependency</string> <string>4.IBPluginDependency</string>
<string>6.IBPluginDependency</string> <string>6.IBPluginDependency</string>
</object> </object>
<object class="NSMutableArray" key="dict.values"> <object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>GTMOAuth2ViewControllerTouch</string> <string>GTMOAuth2ViewControllerTouch</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>UIResponder</string> <string>UIResponder</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>{{34, 1031}, {60, 30}}</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>{{214, 696}, {320, 460}}</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>
@@ -339,20 +389,16 @@
<object class="NSMutableDictionary" key="unlocalizedProperties"> <object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/> <reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values"> <reference key="dict.values" ref="0"/>
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object> </object>
<nil key="activeLocalization"/> <nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations"> <object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/> <reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values"> <reference key="dict.values" ref="0"/>
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object> </object>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">29</int> <int key="maxID">33</int>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"> <object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions"> <object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -365,21 +411,19 @@
<object class="NSArray" key="dict.sortedKeys"> <object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>backButton</string> <string>backButton</string>
<string>delegate_</string>
<string>forwardButton</string> <string>forwardButton</string>
<string>initialActivityIndicator</string>
<string>navButtonsView</string> <string>navButtonsView</string>
<string>rightBarButtonItem</string> <string>rightBarButtonItem</string>
<string>userData_</string>
<string>webView</string> <string>webView</string>
</object> </object>
<object class="NSMutableArray" key="dict.values"> <object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>UIButton</string> <string>UIButton</string>
<string>id</string>
<string>UIButton</string> <string>UIButton</string>
<string>UIActivityIndicatorView</string>
<string>UIView</string> <string>UIView</string>
<string>UIBarButtonItem</string> <string>UIBarButtonItem</string>
<string>id</string>
<string>UIWebView</string> <string>UIWebView</string>
</object> </object>
</object> </object>
@@ -388,27 +432,26 @@
<object class="NSArray" key="dict.sortedKeys"> <object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<string>backButton</string> <string>backButton</string>
<string>delegate_</string>
<string>forwardButton</string> <string>forwardButton</string>
<string>initialActivityIndicator</string>
<string>navButtonsView</string> <string>navButtonsView</string>
<string>rightBarButtonItem</string> <string>rightBarButtonItem</string>
<string>userData_</string>
<string>webView</string> <string>webView</string>
</object> </object>
<object class="NSMutableArray" key="dict.values"> <object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">backButton</string> <string key="name">backButton</string>
<string key="candidateClassName">UIButton</string> <string key="candidateClassName">UIButton</string>
</object> </object>
<object class="IBToOneOutletInfo">
<string key="name">delegate_</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">forwardButton</string> <string key="name">forwardButton</string>
<string key="candidateClassName">UIButton</string> <string key="candidateClassName">UIButton</string>
</object> </object>
<object class="IBToOneOutletInfo">
<string key="name">initialActivityIndicator</string>
<string key="candidateClassName">UIActivityIndicatorView</string>
</object>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">navButtonsView</string> <string key="name">navButtonsView</string>
<string key="candidateClassName">UIView</string> <string key="candidateClassName">UIView</string>
@@ -417,10 +460,6 @@
<string key="name">rightBarButtonItem</string> <string key="name">rightBarButtonItem</string>
<string key="candidateClassName">UIBarButtonItem</string> <string key="candidateClassName">UIBarButtonItem</string>
</object> </object>
<object class="IBToOneOutletInfo">
<string key="name">userData_</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">webView</string> <string key="name">webView</string>
<string key="candidateClassName">UIWebView</string> <string key="candidateClassName">UIWebView</string>
@@ -429,7 +468,7 @@
</object> </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string> <string key="majorKey">IBProjectSource</string>
<string key="minorKey">Touch/GTMOAuth2ViewControllerTouch.h</string> <string key="minorKey">./Classes/GTMOAuth2ViewControllerTouch.h</string>
</object> </object>
</object> </object>
</object> </object>
@@ -438,19 +477,18 @@
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string> <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
<integer value="768" key="NS.object.0"/> <real value="1024" key="NS.object.0"/>
</object> </object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults"> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
<integer value="800" key="NS.object.0"/> <real value="1536" key="NS.object.0"/>
</object> </object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
<integer value="3000" key="NS.object.0"/> <integer value="3000" key="NS.object.0"/>
</object> </object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<string key="IBDocument.LastKnownRelativeProjectPath">../GTMOAuth2.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int> <int key="IBDocument.defaultPropertyAccessControl">3</int>
<string key="IBCocoaTouchPluginVersion">141</string> <string key="IBCocoaTouchPluginVersion">1926</string>
</data> </data>
</archive> </archive>

View File

@@ -0,0 +1,54 @@
// Copyright 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/Foundation.h>
// This class is used to check if Google Chrome is installed in the system and
// to open a URL in Google Chrome either with or without a callback URL.
@interface OpenInChromeController : NSObject
// Returns a shared instance of the OpenInChromeController.
+ (OpenInChromeController *)sharedInstance;
// Returns YES if Google Chrome is installed in the user's system.
- (BOOL)isChromeInstalled;
// Opens a URL in Google Chrome.
- (BOOL)openInChrome:(NSURL *)url;
// Open a URL in Google Chrome providing a |callbackURL| to return to the app.
// URLs from the same app will be opened in the same tab unless |createNewTab|
// is set to YES.
// |callbackURL| can be nil.
// The return value of this method is YES if the URL is successfully opened.
- (BOOL)openInChrome:(NSURL *)url
withCallbackURL:(NSURL *)callbackURL
createNewTab:(BOOL)createNewTab;
@end

View File

@@ -0,0 +1,135 @@
// Copyright 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <UIKit/UIKit.h>
#import "OpenInChromeController.h"
static NSString * const kGoogleChromeHTTPScheme = @"googlechrome:";
static NSString * const kGoogleChromeHTTPSScheme = @"googlechromes:";
static NSString * const kGoogleChromeCallbackScheme =
@"googlechrome-x-callback:";
static NSString * encodeByAddingPercentEscapes(NSString *input) {
NSString *encodedValue =
(NSString *)CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(CFStringRef)input,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8);
return [encodedValue autorelease];
}
@implementation OpenInChromeController
+ (OpenInChromeController *)sharedInstance {
static OpenInChromeController *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (BOOL)isChromeInstalled {
NSURL *simpleURL = [NSURL URLWithString:kGoogleChromeHTTPScheme];
NSURL *callbackURL = [NSURL URLWithString:kGoogleChromeCallbackScheme];
return [[UIApplication sharedApplication] canOpenURL:simpleURL] ||
[[UIApplication sharedApplication] canOpenURL:callbackURL];
}
- (BOOL)openInChrome:(NSURL *)url {
return [self openInChrome:url withCallbackURL:nil createNewTab:NO];
}
- (BOOL)openInChrome:(NSURL *)url
withCallbackURL:(NSURL *)callbackURL
createNewTab:(BOOL)createNewTab {
NSURL *chromeSimpleURL = [NSURL URLWithString:kGoogleChromeHTTPScheme];
NSURL *chromeCallbackURL = [NSURL URLWithString:kGoogleChromeCallbackScheme];
if ([[UIApplication sharedApplication] canOpenURL:chromeCallbackURL]) {
NSString *appName =
[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"CFBundleDisplayName"];
NSString *scheme = [url.scheme lowercaseString];
// Proceed only if scheme is http or https.
if ([scheme isEqualToString:@"http"] ||
[scheme isEqualToString:@"https"]) {
NSMutableString *chromeURLString = [NSMutableString string];
[chromeURLString appendFormat:
@"%@//x-callback-url/open/?x-source=%@&url=%@",
kGoogleChromeCallbackScheme,
encodeByAddingPercentEscapes(appName),
encodeByAddingPercentEscapes([url absoluteString])];
if (callbackURL) {
[chromeURLString appendFormat:@"&x-success=%@",
encodeByAddingPercentEscapes([callbackURL absoluteString])];
}
if (createNewTab) {
[chromeURLString appendString:@"&create-new-tab"];
}
NSURL *chromeURL = [NSURL URLWithString:chromeURLString];
// Open the URL with Google Chrome.
return [[UIApplication sharedApplication] openURL:chromeURL];
}
} else if ([[UIApplication sharedApplication] canOpenURL:chromeSimpleURL]) {
NSString *scheme = [url.scheme lowercaseString];
// Replace the URL Scheme with the Chrome equivalent.
NSString *chromeScheme = nil;
if ([scheme isEqualToString:@"http"]) {
chromeScheme = kGoogleChromeHTTPScheme;
} else if ([scheme isEqualToString:@"https"]) {
chromeScheme = kGoogleChromeHTTPSScheme;
}
// Proceed only if a valid Google Chrome URI Scheme is available.
if (chromeScheme) {
NSString *absoluteString = [url absoluteString];
NSRange rangeForScheme = [absoluteString rangeOfString:@":"];
NSString *urlNoScheme =
[absoluteString substringFromIndex:rangeForScheme.location + 1];
NSString *chromeURLString =
[chromeScheme stringByAppendingString:urlNoScheme];
NSURL *chromeURL = [NSURL URLWithString:chromeURLString];
// Open the URL with Google Chrome.
return [[UIApplication sharedApplication] openURL:chromeURL];
}
}
return NO;
}
@end

View File

@@ -1,16 +1,19 @@
This Google+ iOS SDK allows users to sign in with Google+, share with Google+, This Google+ iOS SDK allows users to sign in and share with Google+ from
and write moments to Google+ history from third-party apps. The SDK contains the third-party apps. The SDK also provides Google+ APIs for the app to access
following files: the list of people in user-selected circles and to read and write user's app
activities. The SDK contains the following files:
README -- This file. README -- This file.
Changelog -- The versions and changes of the SDK. Changelog -- The versions and changes of the SDK.
lib/ -- Header files and libraries. lib/ -- Header files and libraries.
GooglePlusShare.h -- Header file to include for sharing with Google+. GPPDeepLink.h -- Header file to include for sharing with Google+ with content
GooglePlusSignIn.h -- Header file to include for signing into Google+. deep linking.
GooglePlusSignInButton.h -- Header file to include for showing a button to GPPShare.h -- Header file to include for sharing with Google+.
sign in with Google+. GPPSignIn.h -- Header file to include for signing into Google+.
GPPSignInButton.h -- Header file to include for showing a button to
sign in with Google+.
libGooglePlus.a -- Static library built for iOS device to link into your app. libGooglePlus.a -- Static library built for iOS device to link into your app.
libGooglePlusUniversal.a -- Static library built for both iOS device and libGooglePlusUniversal.a -- Static library built for both iOS device and
simulator to link into your app. simulator to link into your app.
@@ -20,19 +23,11 @@ OpenSource/ -- Google open source files used by the SDK. Add all files in this
Also see comments for the subdirectory below. Also see comments for the subdirectory below.
GTL/ -- Google open source files only used by the sample app. Include them GTL/ -- Google open source files only used by the sample app. Include them
into your project if you're going to use the same functionality, into your project if you're going to use the same functionality,
e.g. Add Moments. e.g. writing user's app activities.
Resources/ -- Resources that can be used in your app. Resources/ -- Resources that can be used in your app.
For |GooglePlusSignInButton|, the google_plus_sign_in*.png images For |GPPSignInButton|, the gpp_sign_in_*.png images
are required. are required.
google_plus_share.png -- 82x24 Google+ share button image.
google_plus_share_large.png -- 112x32 Google+ share button image.
google_plus_share@2x.png -- 164x48 Google+ share button image.
google_plus_share_large@2x.png -- 224x64 Google+ share button image.
google_plus_sign_in.png -- 120x32 Google+ sign-in button image.
google_plus_sign_in_wide.png --220x32 Wide Google+ sign-in button image.
google_plus_sign_in@2x.png -- 240x64 Google+ sign-in button image.
google_plus_sign_in_wide@2x.png -- 440x64 Wide Google+ sign-in button image.
SampleCode/ -- Sample code for your reference only. SampleCode/ -- Sample code for your reference only.
Do not include this in your project. Do not include this in your project.

View File

@@ -0,0 +1,5 @@
/* Sign-in button text */
"Sign in" = "Meld aan";
/* Long form sign-in button text */
"Sign in with Google" = "Meld aan met Google";

View File

@@ -0,0 +1,5 @@
/* Sign-in button text */
"Sign in" = "ይግቡ";
/* Long form sign-in button text */
"Sign in with Google" = "በGoogle ይግቡ";

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