Show AdMob Native Ads with MoPub (iOS) - ios

I am integrating MoPub SDK to mediate ADs from the Google AdMob network. I can get the AD to show after implementing my own customEvent and Adapter, but i can't get the AD to handle click events on its own. As in when I click on the AdMob native AD, it won't direct me anywhere. When using Facebook and Flurry's CustomEvent and Adapter, clicks are handled automatically. Anyone have any experience on this subject?
Thanks in Advance. Code below:
MPGoogleAdMobCustomEvent
#interface MPGoogleAdMobCustomEvent()
#property(nonatomic, strong)GADAdLoader *loader;
#end
#implementation MPGoogleAdMobCustomEvent
- (void)requestAdWithCustomEventInfo:(NSDictionary *)info
{
MPLogInfo(#"MOPUB: requesting AdMob Native Ad");
NSString *adUnitID = [info objectForKey:#"adUnitID"];
if (!adUnitID) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:MPNativeAdNSErrorForInvalidAdServerResponse(#"MOPUB: No AdUnitID from GoogleAdMob")];
return;
}
self.loader = [[GADAdLoader alloc] initWithAdUnitID:adUnitID rootViewController:nil adTypes:#[kGADAdLoaderAdTypeNativeContent] options:nil];
self.loader.delegate = self;
GADRequest *request = [GADRequest request];
#if (TARGET_OS_SIMULATOR)
request.testDevices = #[ kGADSimulatorID ];
#endif
CLLocation *location = [[CLLocationManager alloc] init].location;
if (location) {
[request setLocationWithLatitude:location.coordinate.latitude
longitude:location.coordinate.longitude
accuracy:location.horizontalAccuracy];
}
request.requestAgent = #"MoPub";
[self.loader loadRequest:request];
}
- (void)adLoader:(GADAdLoader *)adLoader didReceiveNativeContentAd:(GADNativeContentAd *)nativeContentAd
{
MPLogDebug(#"MOPUB: Did receive nativeAd");
MPGoogleAdMobNativeAdAdapter *adapter = [[MPGoogleAdMobNativeAdAdapter alloc] initWithGADNativeContentAd:nativeContentAd];
adapter.url = nativeContentAd.advertiser;
MPNativeAd *interfaceAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
NSMutableArray *imageArray = [NSMutableArray array];
for (GADNativeAdImage *images in nativeContentAd.images) {
[imageArray addObject:images.imageURL];
}
[super precacheImagesWithURLs:imageArray completionBlock:^(NSArray *errors) {
if ([errors count]) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:errors[0]];
} else {
[self.delegate nativeCustomEvent:self didLoadAd:interfaceAd];
}
}];
}
- (void)adLoader:(GADAdLoader *)adLoader didFailToReceiveAdWithError:(GADRequestError *)error
{
MPLogDebug(#"MOPUB: AdMob ad failed to load with error (customEvent): %#", error.description);
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:error];
}
#end
MPGoogleAdMobNativeAdAdapter
#interface MPGoogleAdMobNativeAdAdapter()<GADNativeAdDelegate>
#property(nonatomic, strong)NSDictionary *properties;
#end
#implementation MPGoogleAdMobNativeAdAdapter
- (instancetype)initWithGADNativeContentAd:(GADNativeContentAd *)contentAD
{
self = [super init];
if (self) {
self.contentAd = contentAD;
self.contentAd.delegate = self;
self.properties = [self convertAssetsToProperties:contentAD];
}
return self;
}
- (NSDictionary *)convertAssetsToProperties:(GADNativeContentAd *)adNative
{
self.contentAd = adNative;
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
if (adNative.headline) {
dictionary[kAdTitleKey] = adNative.headline;
}
if (adNative.body) {
dictionary[kAdTextKey] = adNative.body;
}
if (adNative.images[0]) {
dictionary[kAdMainImageKey] = ((GADNativeAdImage *)adNative.images[0]).imageURL.absoluteString;
}
if (adNative.callToAction) {
dictionary[kAdCTATextKey] = adNative.callToAction;
}
return [dictionary copy];
}
#pragma mark MPNativeAdAdapter
- (NSTimeInterval)requiredSecondsForImpression
{
return 0.0;
}
- (NSURL *)defaultActionURL
{
return nil;
}
- (BOOL)enableThirdPartyClickTracking
{
return YES;
}
- (void)willAttachToView:(UIView *)view
{
self.contentAd.rootViewController = [self.delegate viewControllerForPresentingModalView];
}
- (void)didDetachFromView:(UIView *)view
{
self.contentAd.rootViewController = nil;
}
#pragma mark GADNativeAdDelegate
- (void)nativeAdWillPresentScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillPresentModalForAdapter:)]) {
[self.delegate nativeAdWillPresentModalForAdapter:self];
}
}
- (void)nativeAdDidDismissScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdDidDismissModalForAdapter:)]) {
[self.delegate nativeAdDidDismissModalForAdapter:self];
}
}
- (void)nativeAdWillLeaveApplication:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillLeaveApplicationFromAdapter:)]) {
[self.delegate nativeAdWillLeaveApplicationFromAdapter:self];
}
}
#end
`

If you are having your custom UI for AdMob Ad's, then there will be a button which you will be using for callToAction part.
First of all you need to add a selector to detect action of click, to do add the selector for that button
[callToActionButton addTarget:self action:#selector(adCalled:) forControlEvents:UIControlEventTouchUpInside];
After that implement the adCalled method to get the click & call the method further, below is the code for your reference
Below is the example which I have used to get the ad object from my collection view & then I am redirecting it.
- (void)adCalled:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:mainCollectionView]; // Get the button position
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:buttonPosition]; // Get the index path of button so that I can retrieve the correct ad object
id selectedAd = [adArray objectAtIndex:indexPath.row];
if ([selectedAd isKindOfClass:[GADNativeContentAd class]]) {
NSString *url = [selectedAd valueForKey:#"googleClickTrackingURLString"];
NSLog(#"URL is :%#", url);
NSURL *googleUrl = [NSURL URLWithString:url];
if ([[UIApplication sharedApplication] canOpenURL: googleUrl]) {
[[UIApplication sharedApplication] openURL:googleUrl];
}
}
}
Using this I can open the link n web using the google tracking url.
Hope this helps.

Related

Manage incoming Call with 2 sdk (CALL KIT & VoIP SDK) simultaneously?

#import "AppDelegate.h"
#import <Intents/Intents.h>
#import <CallKit/CallKit.h>
#import <PushKit/PushKit.h>
#pragma mark - PKPushRegistryDelegate
- (void)pushRegistry:(nonnull PKPushRegistry *)registry didUpdatePushCredentials:(nonnull PKPushCredentials *)pushCredentials forType:(nonnull PKPushType)type {
if ([pushCredentials.token length] == 0) {
NSLog(#"VoIP token NULL..");
}
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type
{
NSString *uuidString = payload.dictionaryPayload[#"UUID"];
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
NSString *phoneNumber = payload.dictionaryPayload[#"PhoneNumber"];
CallViewController *viewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"CallViewController"];
viewController.number = phoneNumber;
viewController.incoming = YES;
viewController.callId = uuid;
UIViewController *mainViewController = self.window.rootViewController;
[mainViewController presentViewController:viewController animated:YES completion:nil];
}
#import "CallManager.h"
#import <CallKit/CallKit.h>
#import <CallKit/CXError.h>
#interface CallManager () <CXProviderDelegate>
#property (nonatomic, strong) CXProvider *provider;
#property (nonatomic, strong) CXCallController *callController;
#property (nonatomic, strong) NSUUID *currentCall;
#end
#implementation CallManager
+ (CallManager*)shaaredInstance {
static CallManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[CallManager alloc] init];
[sharedInstance provider];
});
return sharedInstance;
}
- (void)reportIncomingCallForUUID:(NSUUID*)uuid phoneNumber:(NSString*)phoneNumber {
CXCallUpdate *update = [[CXCallUpdate alloc] init];
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:phoneNumber];
__weak CallManager *weakSelf = self;
[self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError * _Nullable error) {
if (!error) {
weakSelf.currentCall = uuid;
} else {
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidFail)]) {
[self.delegate callDidFail];
}
}
}];
}
- (void)startCallWithPhoneNumber:(NSString*)phoneNumber {
CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:phoneNumber];
self.currentCall = [NSUUID new];
CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:self.currentCall handle:handle];
CXTransaction *transaction = [[CXTransaction alloc] init];
[transaction addAction:startCallAction];
[self requestTransaction:transaction];
}
- (void)endCall {
CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:self.currentCall];
CXTransaction *transaction = [[CXTransaction alloc] init];
[transaction addAction:endCallAction];
[self requestTransaction:transaction];
}
- (void)holdCall:(BOOL)hold {
CXSetHeldCallAction *holdCallAction = [[CXSetHeldCallAction alloc] initWithCallUUID:self.currentCall onHold:hold];
CXTransaction *transaction = [[CXTransaction alloc] init];
[transaction addAction:holdCallAction];
[self requestTransaction:transaction];
}
- (void)requestTransaction:(CXTransaction*)transaction {
[self.callController requestTransaction:transaction completion:^(NSError * _Nullable error) {
if (error) {
NSLog(#"%#", error.localizedDescription);
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidFail)]) {
[self.delegate callDidFail];
}
}
}];
}
#pragma mark - Getters
- (CXProvider*)provider {
if (!_provider) {
CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:#"IP-PBX"];
configuration.supportsVideo = YES;
configuration.maximumCallsPerCallGroup = 1;
configuration.supportedHandleTypes = [NSSet setWithObject:#(CXHandleTypePhoneNumber)];
_provider = [[CXProvider alloc] initWithConfiguration:configuration];
[_provider setDelegate:self queue:nil];
}
return _provider;
}
- (CXCallController*)callController {
if (!_callController) {
_callController = [[CXCallController alloc] init];
}
return _callController;
}
#pragma mark - CXProviderDelegate
- (void)providerDidReset:(CXProvider *)provider {
}
// Called when the provider has been fully created and is ready to send actions and receive updates
- (void)providerDidBegin:(CXProvider *)provider {
}
// If provider:executeTransaction:error: returned NO, each perform*CallAction method is called sequentially for each action in the transaction
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
//todo: configure audio session
//todo: start network call
[self.provider reportOutgoingCallWithUUID:action.callUUID startedConnectingAtDate:nil];
[self.provider reportOutgoingCallWithUUID:action.callUUID connectedAtDate:nil];
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidAnswer)]) {
[self.delegate callDidAnswer];
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
//todo: configure audio session
//todo: answer network call
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidAnswer)]) {
[self.delegate callDidAnswer];
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
//todo: stop audio
//todo: end network call
self.currentCall = nil;
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidEnd)]) {
[self.delegate callDidEnd];
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performSetHeldCallAction:(CXSetHeldCallAction *)action {
if (action.isOnHold) {
//todo: stop audio
} else {
//todo: start audio
}
if (self.delegate && [self.delegate respondsToSelector:#selector(callDidHold:)]) {
[self.delegate callDidHold:action.isOnHold];
}
[action fulfill];
}
I am using Call Kit in VOIP application (using ABTO VoIP SDK too). But I want to merge my VoiP App call history to my iPHONE recent tab. I added Call kit in my project everything was fine I am getting VoIP app call history to my iPhone recent tab. But I am facing issues while calling once I do incoming or outgoing calls I am getting callkit default screen which lead the incoming call on hold and outgoing to. Would there any way to manage callkit default screen? Would it be possible to manage two SDK at the same time??? I am using pushkit too..
Please help me to resolve this issue????
Whenever I am getting incoming call I am facing 2 calling screen one from Voip SDK and one from Call kit.. I want to manage that default screen

Background fetch and refresh completed after viewDidLoad in iOS 10

I'm trying to implement background fetch as well as refresh in iOS 10.
I'm using XML parsing to parse the data and then storing it in a file in the document's directory. For parsing XML I'm using a custom class (XMLParser) that confirms the NSXMLParserDelegate protocol.
The background fetch works fine. But I'm having problems in displaying the refreshed data, both when I click on the refresh button as well as in viewDidLoad.
I'm calling the refreshData method in viewDidLoad.
Here's how far I've gotten.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//--Set background fetch--//
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
}
...
#pragma mark Background data fetch methods
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSDate *fetchStart = [NSDate date];
ArtsViewController *artsViewController = (ArtsViewController *)self.window.rootViewController;
[artsViewController fetchNewDataWithCompletionHandler:^(UIBackgroundFetchResult result) {
completionHandler(result);
NSDate *fetchEnd = [NSDate date];
NSTimeInterval timeElapsed = [fetchEnd timeIntervalSinceDate:fetchStart];
NSLog(#"Background Fetch Duration: %f seconds", timeElapsed);
}];
}
ArtsViewController.h
#interface ArtsViewController : UIViewController <UIPageViewControllerDataSource>
#property BOOL newsAvailable;
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler; // No problems here
#end
ArtsViewcontroller.m
#interface ArtsViewController ()
#property (nonatomic, strong) NSArray *arrNewsData;
-(void)refreshData;
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray;
#end
...
#implementation ArtsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self refreshData];
//--Load the file that saves news--//
[self loadNews];
if (_newsAvailable == YES)
{
[self setupPageViewController];
}
else
{
[self showNoNewsMessage];
}
}
...
#pragma mark Data Fetch methods
-(void)refreshData{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:ArtsNewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
[self performNewFetchedDataActionsWithDataArray:dataArray];
}
else{
NSLog(#"%#", [error localizedDescription]);
}
}];
}
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray{
// 1. Initialize the arrNewsData array with the parsed data array.
if (self.arrNewsData != nil) {
self.arrNewsData = nil;
}
self.arrNewsData = [[NSArray alloc] initWithArray:dataArray];
// 2. Write the file and reload the view.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * docDirectory = [paths objectAtIndex:0];
NSString * newsFilePath = [NSString stringWithFormat:#"%#",[docDirectory stringByAppendingPathComponent:#"arts2"]]; // NewsFile
if (![self.arrNewsData writeToFile:newsFilePath atomically:YES]) {
_newsAvailable = NO;
NSLog(#"Couldn't save data.");
}
else
{
_newsAvailable = YES;
NSLog(#"Saved data.");
[self viewWillAppear:YES];
}
}
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:ArtsNewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
NSDictionary *latestDataDict = [dataArray objectAtIndex:0];
NSString *latestTitle = [latestDataDict objectForKey:#"title"];
NSDictionary *existingDataDict = [self.arrNewsData objectAtIndex:0];
NSString *existingTitle = [existingDataDict objectForKey:#"title"];
if ([latestTitle isEqualToString:existingTitle]) {
completionHandler(UIBackgroundFetchResultNoData);
NSLog(#"No new data found.");
}
else{
[self performNewFetchedDataActionsWithDataArray:dataArray];
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"New data was fetched.");
}
}
else{
completionHandler(UIBackgroundFetchResultFailed);
NSLog(#"Failed to fetch new data.");
}
}];
}
...
#pragma mark IBActions
- (IBAction)reloadNews:(UIBarButtonItem *)sender
{
[self viewDidLoad];
}
I've debugged the application and found that after viewDidLoad
completes execution, the data file is written but the view isn't
updated. I've also tried calling the refreshData method in the main
thread, but there's no change.
after viewDidLoad is complete the showNoNewNews method is called.
I'm suspecting that my logic isn't wrong but implementation is. Threads at play here..
Any help would be appreciated.
Update:
Hope this helps those with similar problems...
I moved the logic of viewDidLoad to a different method, called the method for the first time in viewDidLoad and again in refreshData, after
[self performNewFetchedDataActionsWithDataArray:dataArray];

Azure AD B2C getting oauthConnection Error: Bad Request

While trying to integrate Azure AD B2C, I am stuck with an error "oauthConnection Error: Bad Request". Following their given sample app it all works fine. But after integrating the same copy paste code from the working sample app, and trying to log in with Facebook or Google Plus, it throws an error! I am pretty sure that every credential that I used in the sample app is the same for my app. Any idea about this will be highly appreciated. Here is my code, AppDelegate.m
#import "AppData.h"
#import "NXOAuth2.h"
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self setupOAuth2AccountStore];
// Override point for customization after application launch.
return YES;
}
- (void)setupOAuth2AccountStore {
AppData *data = [AppData getInstance]; // The singleton we use to get the settings
NSDictionary *customHeaders =
[NSDictionary dictionaryWithObject:#"application/x-www-form-urlencoded"
forKey:#"Content-Type"];
// Azure B2C needs
// kNXOAuth2AccountStoreConfigurationAdditionalAuthenticationParameters for
// sending policy to the server,
// therefore we use -setConfiguration:forAccountType:
NSDictionary *B2cConfigDict = #{
kNXOAuth2AccountStoreConfigurationClientID : data.clientID,
kNXOAuth2AccountStoreConfigurationSecret : data.clientSecret,
kNXOAuth2AccountStoreConfigurationScope :
[NSSet setWithObjects:#"openid", data.clientID, nil],
kNXOAuth2AccountStoreConfigurationAuthorizeURL :
[NSURL URLWithString:data.authURL],
kNXOAuth2AccountStoreConfigurationTokenURL :
[NSURL URLWithString:data.tokenURL],
kNXOAuth2AccountStoreConfigurationRedirectURL :
[NSURL URLWithString:data.bhh],
kNXOAuth2AccountStoreConfigurationCustomHeaderFields : customHeaders,
// kNXOAuth2AccountStoreConfigurationAdditionalAuthenticationParameters:customAuthenticationParameters
};
[[NXOAuth2AccountStore sharedStore] setConfiguration:B2cConfigDict
forAccountType:data.accountIdentifier];
}
LoginViewController.m
#import "AppData.h"
#import "LoginViewController.h"
#import "NXOAuth2.h"
#interface LoginViewController ()
#end
#implementation LoginViewController {
NSURL *myLoadedUrl;
bool isRequestBusy;
}
// Put variables here
- (void)viewDidLoad {
[super viewDidLoad];
// OAuth2 Code
self.loginView.delegate = self;
[self requestOAuth2Access];
[self setupOAuth2AccountStore];
NSURLCache *URLCache =
[[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
}
- (void)resolveUsingUIWebView:(NSURL *)URL {
// We get the auth token from a redirect so we need to handle that in the
// webview.
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(resolveUsingUIWebView:)
withObject:URL
waitUntilDone:YES];
return;
}
NSURLRequest *hostnameURLRequest =
[NSURLRequest requestWithURL:URL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0f];
isRequestBusy = YES;
[self.loginView loadRequest:hostnameURLRequest];
NSLog(#"resolveUsingUIWebView ready (status: UNKNOWN, URL: %#)",
self.loginView.request.URL);
}
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
AppData *data = [AppData getInstance];
NSLog(#"webView:shouldStartLoadWithRequest: %# (%li)", request.URL,
(long)navigationType);
// The webview is where all the communication happens. Slightly complicated.
myLoadedUrl = [webView.request mainDocumentURL];
NSLog(#"***Loaded url: %#", myLoadedUrl);
// if the UIWebView is showing our authorization URL or consent URL, show the
// UIWebView control
if ([request.URL.absoluteString rangeOfString:data.authURL
options:NSCaseInsensitiveSearch]
.location != NSNotFound) {
self.loginView.hidden = NO;
} else if ([request.URL.absoluteString rangeOfString:data.loginURL
options:NSCaseInsensitiveSearch]
.location != NSNotFound) {
// otherwise hide the UIWebView, we've left the authorization flow
self.loginView.hidden = NO;
} else if ([request.URL.absoluteString rangeOfString:data.bhh
options:NSCaseInsensitiveSearch]
.location != NSNotFound) {
// otherwise hide the UIWebView, we've left the authorization flow
self.loginView.hidden = YES;
[[NXOAuth2AccountStore sharedStore] handleRedirectURL:request.URL];
} else {
self.loginView.hidden = NO;
}
return YES;
}
#pragma mark - UIWebViewDelegate methods
- (void)webViewDidFinishLoad:(UIWebView *)webView {
// The webview is where all the communication happens. Slightly complicated.
}
- (void)handleOAuth2AccessResult:(NSURL *)accessResult {
// parse the response for success or failure
if (accessResult)
// if success, complete the OAuth2 flow by handling the redirect URL and
// obtaining a token
{
[[NXOAuth2AccountStore sharedStore] handleRedirectURL:accessResult];
} else {
// start over
[self requestOAuth2Access];
}
}
- (void)setupOAuth2AccountStore {
[[NSNotificationCenter defaultCenter]
addObserverForName:NXOAuth2AccountStoreAccountsDidChangeNotification
object:[NXOAuth2AccountStore sharedStore]
queue:nil
usingBlock:^(NSNotification *aNotification) {
if (aNotification.userInfo) {
// account added, we have access
// we can now request protected data
NSLog(#"Success!! We have an access token.");
} else {
// account removed, we lost access
}
}];
[[NSNotificationCenter defaultCenter]
addObserverForName:NXOAuth2AccountStoreDidFailToRequestAccessNotification
object:[NXOAuth2AccountStore sharedStore]
queue:nil
usingBlock:^(NSNotification *aNotification) {
NSError *error = [aNotification.userInfo
objectForKey:NXOAuth2AccountStoreErrorKey];
// Always got stuck here while trying to login with any credentials
NSLog(#"Error!! %#", error.localizedDescription);
}];
}
- (void)requestOAuth2Access {
AppData *data = [AppData getInstance];
[[NXOAuth2AccountStore sharedStore]
requestAccessToAccountWithType:data.accountIdentifier
withPreparedAuthorizationURLHandler:^(NSURL *preparedURL) {
NSURLRequest *r = [NSURLRequest requestWithURL:preparedURL];
[self.loginView loadRequest:r];
}];
}
ViewController.m
#import "ViewController.h"
#import "AppData.h"
#import "LoginViewController.h"
#import "NXOAuth2.h"
// Login Action
- (IBAction)login:(id)sender {
LoginViewController *userSelectController =
[self.storyboard instantiateViewControllerWithIdentifier:#"login"];
[self.navigationController pushViewController:userSelectController
animated:YES];
}
In case if anybody stumbles in this, Here is the solution
Go to pod, NXOAuth2Client.m and replace the method
- (void)requestTokenWithAuthGrant:(NSString *)authGrant redirectURL:(NSURL *)redirectURL; with the below code
- (void)requestTokenWithAuthGrant:(NSString *)authGrant redirectURL:(NSURL *)redirectURL;
{
NSAssert1(!authConnection, #"authConnection already running with: %#", authConnection);
NSMutableURLRequest *tokenRequest = [NSMutableURLRequest requestWithURL:tokenURL];
[tokenRequest setHTTPMethod:self.tokenRequestHTTPMethod];
[authConnection cancel]; // just to be sure
self.authenticating = YES;
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"authorization_code", #"grant_type",
clientId, #"client_id",
// clientSecret, #"client_secret",
[redirectURL absoluteString], #"redirect_uri",
authGrant, #"code",
nil];
if (self.desiredScope) {
[parameters setObject:[[self.desiredScope allObjects] componentsJoinedByString:#" "] forKey:#"scope"];
}
if (self.customHeaderFields) {
[self.customHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
[tokenRequest addValue:obj forHTTPHeaderField:key];
}];
}
if (self.additionalAuthenticationParameters) {
[parameters addEntriesFromDictionary:self.additionalAuthenticationParameters];
}
authConnection = [[NXOAuth2Connection alloc] initWithRequest:tokenRequest
requestParameters:parameters
oauthClient:self
delegate:self];
authConnection.context = NXOAuth2ClientConnectionContextTokenRequest;
}
Commenting clientSecret solved the issue

Authentication error - Integration SkyDrive in iOS application

I am trying to integrate SkyDrive in my iOS application and the following is the code where I have written the login authentication code. The client ID provided here is the one assigned for the application at the developer site. But the authentication always fails. Any idea what is the error ?
static NSString * const CLIENT_ID = #"00000000XXXXXXXXX";
#implementation PSMainViewController
#synthesize appLogo;
#synthesize userInfoLabel;
#synthesize signInButton;
#synthesize viewPhotosButton;
#synthesize userImage;
#synthesize liveClient;
#synthesize currentModal;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
_scopes = [NSArray arrayWithObjects:
#"wl.signin",
#"wl.basic",
#"wl.skydrive",
#"wl.offline_access", nil];
liveClient = [[LiveConnectClient alloc] initWithClientId:CLIENT_ID
scopes:_scopes
delegate:self];
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.appLogo.image = [UIImage imageNamed:#"skydrive.jpeg"];
[self updateUI];
}
- (void)viewDidUnload
{
[self setAppLogo:nil];
[self setUserInfoLabel:nil];
[self setUserImage:nil];
[self setSignInButton:nil];
[self setViewPhotosButton:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)signinButtonClicked:(id)sender {
if (self.liveClient.session == nil)
{
[self.liveClient login:self
scopes:_scopes
delegate:self];
}
else
{
[self.liveClient logoutWithDelegate:self
userState:#"logout"];
}
}
- (IBAction)viewPhotoButtonClicked:(id)sender {
// Create a Navigation controller
PSSkyPhotoViewer *aPhotoViewer = [[PSSkyPhotoViewer alloc] initWithNibName:#"PSSkyPhotoViewer" bundle:nil];
aPhotoViewer.parentVC = self;
self.currentModal = [[UINavigationController alloc] initWithRootViewController:aPhotoViewer];
[self presentModalViewController:self.currentModal animated:YES];
}
- (void) modalCompleted:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
self.currentModal = nil;
}
#pragma mark LiveAuthDelegate
- (void) updateUI {
LiveConnectSession *session = self.liveClient.session;
if (session == nil) {
[self.signInButton setTitle:#"Sign in" forState:UIControlStateNormal];
self.viewPhotosButton.hidden = YES;
self.userInfoLabel.text = #"Sign in with a Microsoft account before you can view your SkyDrive photos.";
self.userImage.image = nil;
}
else {
[self.signInButton setTitle:#"Sign out" forState:UIControlStateNormal];
self.viewPhotosButton.hidden = NO;
self.userInfoLabel.text = #"";
[self.liveClient getWithPath:#"me" delegate:self userState:#"me"];
[self.liveClient getWithPath:#"me/picture" delegate:self userState:#"me-picture"];
}
}
- (void) authCompleted: (LiveConnectSessionStatus) status
session: (LiveConnectSession *) session
userState: (id) userState {
[self updateUI];
}
- (void) authFailed: (NSError *) error
userState: (id)userState {
// Handle error here
}
#pragma mark LiveOperationDelegate
- (void) liveOperationSucceeded:(LiveOperation *)operation {
if ([operation.userState isEqual:#"me"]) {
NSDictionary *result = operation.result;
id name = [result objectForKey:#"name"];
self.userInfoLabel.text = (name != nil)? name : #"";
}
if ([operation.userState isEqual:#"me-picture"]) {
NSString *location = [operation.result objectForKey:#"location"];
if (location) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:location]];
self.userImage.image = [UIImage imageWithData:data];
}
}
}
- (void) liveOperationFailed:(NSError *)error operation:(LiveOperation *)operation
{
// Handle error here.
}
#end
May be you are not providing the redirect url in case of a desktop application.But if it's the mobile application the you have to check the "Mobile or Desktop client app: " as yes in the api settings

OAuth, Tumblr and Scope

I'm trying to login to Tumblr via OAuth and a Mac App I begin to code.
I donwloaded gtm-oauth source code, everything is fine.
I just began with this code inside a view controller :
- (GTMOAuthAuthentication *)myCustomAuth {
GTMOAuthAuthentication *auth;
auth = [[[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:kConsumerKey
privateKey:kConsumerSecret] autorelease];
auth.serviceProvider = #"Custom Auth Service";
return auth;
}
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error {
NSLog(#"finishedWithAuth");
if (error != nil) {
NSLog(#"failed");
} else {
NSLog(#"done");
}
}
- (void)signInToCustomService {
GTMOAuthAuthentication *auth = [self myCustomAuth];
if (auth == nil) {
NSLog(#"A valid consumer key and consumer secret are required for signing in to Tumblr");
}
else
{
NSLog(#"Ok auth");
}
NSURL *requestURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/request_token"];
NSURL *accessURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/access_token"];
NSURL *authorizeURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/authorize"];
NSString *scope = #"http://api.tumblr.com"; // HERE I DON'T KNOW WHAT TO WRITE
GTMOAuthViewControllerTouch *viewController;
viewController = [[[GTMOAuthViewControllerTouch alloc] initWithScope:scope
language:nil
requestTokenURL:requestURL
authorizeTokenURL:authorizeURL
accessTokenURL:accessURL
authentication:auth
appServiceName:#"My App: Custom Service"
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
[self presentModalViewController:viewController animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self signInToCustomService];
}
But nothing happens.
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error;
This method is never called.
Perhaps this is my scope variable. I don't know which value I have to write for it.
Thanks for your help !

Resources