I've tried to add in app purchase to my app to provide users the option to buy the app without iAd. So I searched for a good cocoa pod because the implementation of in app purchase is very heavy. Cause iaphelper seems to be the best I've tried to implement it in my project like this but as you see that doesn't work that well. Anybody an idea how to make this work?
// .h
#interface MenuViewController : UIViewController <ADBannerViewDelegate, SKPaymentTransactionObserver, SKProductsRequestDelegate>
-(IBAction)removeAds:(UIButton *)sender;
-(void)AdsRemoved;
#end
//.m
-(IBAction)removeAds:(UIButton *)sender {
}
-(void)Purchased {
if(![IAPShare sharedHelper].iap) {
NSSet* dataSet = [[NSSet alloc] initWithObjects:#"com.comquas.iap.test", nil];
[IAPShare sharedHelper].iap = [[IAPHelper alloc] initWithProductIdentifiers:dataSet];
}
[IAPShare sharedHelper].iap.production = NO;
[[IAPShare sharedHelper].iap requestProductsWithCompletion:^(SKProductsRequest* request,SKProductsResponse* response)
{
if(response > 0 ) {
SKProduct* product =[[IAPShare sharedHelper].iap.products objectAtIndex:0];
[[IAPShare sharedHelper].iap buyProduct:product
onCompletion:^(SKPaymentTransaction* trans){
if(trans.error)
{
NSLog(#"Fail %#",[trans.error localizedDescription]);
}
else if(trans.transactionState == SKPaymentTransactionStatePurchased) {
[[IAPShare sharedHelper].iap checkReceipt:trans.transactionReceipt AndSharedSecret:#"your sharesecret" onCompletion:^(NSString *response, NSError *error) {
//Convert JSON String to NSDictionary
NSDictionary* rec = [IAPShare toJSON:response];
if([rec[#"status"] integerValue]==0)
{
NSString *productIdentifier = trans.payment.productIdentifier;
[[IAPShare sharedHelper].iap provideContent:productIdentifier];
NSLog(#"SUCCESS %#",response);
NSLog(#"Pruchases %#",[IAPShare sharedHelper].iap.purchasedProducts);
}
else {
NSLog(#"Fail");
}
}];
}
else if(trans.transactionState == SKPaymentTransactionStateFailed) {
NSLog(#"Fail");
}
}];//end of buy product
}
}];
}
There is a really helpful tutorial on In App Purchase with useful classes which will help to integrate In App Purchase less than half an hour.
http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial
If you find any problem afterward, you can visit this blog.
Related
I am trying to integrate Hyperpay payment into React Native project and I have problems with objective-c, I followed an article and found many issues and with searching, I solve them, but still two issues I can't solve because I am not familiar with objective-c
Issue 1,
No known class method for selector 'presentCheckoutForSubmittingTransactionCompletionHandler:cancelHandler:'
Issue 2,
No known class method for selector 'dismissCheckoutAnimated:completion:'
I am sorry if my code is long but I don't to miss something
// RCTCalendarModule.m
#import "HyperPay.h"
#import "UIKit/UIKit.h"
#import <OPPWAMobile/OPPWAMobile.h>
#implementation HyperPay{
RCTResponseSenderBlock onDoneClick;
RCTResponseSenderBlock onCancelClick;
UIViewController *rootViewController;
NSString *isRedirect;
OPPPaymentProvider *provider;
}
// To export a module named RCTCalendarModule
RCT_EXPORT_METHOD(openHyperPay:(NSDictionary *)indic createDialog:(RCTResponseSenderBlock)doneCallback createDialog:(RCTResponseSenderBlock)cancelCallback) {
onDoneClick = doneCallback;
onCancelClick = cancelCallback;
NSArray *events = #[];
if ([indic[#"is_sandbox"] isEqualToString:#"1"]) {
provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeTest];
} else {
provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeLive];
}
OPPCheckoutSettings *checkoutSettings = [[OPPCheckoutSettings alloc] init];
// Set available payment brands for your shop
checkoutSettings.paymentBrands = #[#"VISA", #"MASTER"];
// Set shopper result URL
checkoutSettings.shopperResultURL = #"com.simicart.enterprise.payments://result";
OPPCheckoutProvider *checkoutProvider = [OPPCheckoutProvider checkoutProviderWithPaymentProvider:provider checkoutID:indic[#"checkoutId"]
settings:checkoutSettings];
dispatch_async(dispatch_get_main_queue(), ^{
[OPPCheckoutProvider presentCheckoutForSubmittingTransactionCompletionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
if (error) {
// Executed in case of failure of the transaction for any reason
if (isRedirect && ![isRedirect isEqualToString:#"1"]) {
onCancelClick(#[#"cancel", events]);
}
} else if (transaction.type == OPPTransactionTypeSynchronous) {
// Send request to your server to obtain the status of the synchronous transaction
// You can use transaction.resourcePath or just checkout id to do it
NSDictionary *responeDic = #{#"resourcePath" : transaction.resourcePath};
onDoneClick(#[responeDic, events]);
NSLog(#"%#", transaction.resourcePath);
} else {
// The SDK opens transaction.redirectUrl in a browser
// See 'Asynchronous Payments' guide for more details
}
} cancelHandler:^{
onCancelClick(#[#"cancel", events]);
// Executed if the shopper closes the payment page prematurely
}];
});
}
- (instancetype)init{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(getStatusOder:) name:#"getStatusOrder" object:nil];
}
return self;
}
- (void)getStatusOder:(NSNotification*)noti{
[OPPCheckoutProvider dismissCheckoutAnimated:YES completion:^{
isRedirect = #"1";
NSURL *url = noti.object;
NSString *urlString = [url absoluteString];
NSLog(#"%#", urlString);
if (![urlString isEqualToString:#"com.simicart.enterprise.payments://result"]) {
NSArray *events = #[];
NSDictionary *responeDic = #{#"url" : urlString};
onDoneClick(#[responeDic, events]);
}
}];
}
#end
As Spotify framework is upgraded and new classes like SPTRemoteApp has
been introduced, I got totally frustrated to integrate it in old app
as they have changed almost every thing. So I need help if someone can
tell me these following points how it works. Somehow I feel I can do
login part but about track list and its playback part seems not
properly understandable from the Spotify developer docs for iOS.
How to get login Url from new Spotify framework or how to login by clicking button without checking login URL content.
How to get playlist like previously we get playlist by calling this method
[SPTRequest playlistsForUserInSession:session callback:^(NSError *error, SPTListPage *object) {
playListCount = [object.items count] - 1;
if (object.items) {
[object.items enumerateObjectsUsingBlock:^(SPTPartialPlaylist *obj, NSUInteger idx, BOOL *stop) {
[playlistURI addObject:obj.uri];
if (idx == object.items.count - 1) {
[weakSelf requestsTracks:playlistURI withSession:session];
}
spotifySynching = NO;
}];
}else{
spotifySynching = NO;
[self stopAnimatingTotalSpinner];
[self updateProgressDisplays];
}
}];
How to maintain and renew session, nd when we should renew it.
What is the replacement of these methods
(SPTListPage *)object;
[object requestNextPageWithSession:session callback:^(NSError *error, SPTListPage *object) {
[tracksURI addObjectsFromArray:object.items];
if ([object hasNextPage]) {
[self hasNextTrack:object withSession:session withNewObject:newObject];
}else{
[self requestsTracks:newObject withSession:session];
}
}];
[SPTRequest requestItemAtURI:obj withSession:session callback:^(NSError *error, SPTPlaylistSnapshot *object) {
if (error != nil) {
NSLog(#"*** Auth error: %#", error);
return;
}
[tracksURI addObjectsFromArray:object.firstTrackPage.items];
if ([object.firstTrackPage hasNextPage]) {
[self hasNextTrack:object.firstTrackPage withSession:session withNewObject:newObject];
}else{
[self requestsTracks:newObject withSession:session];
}
}];
Please check and let me know.
Thanks
I have a query regarding concurrency in Azure mobile client SDK.
for windows I found Conflict link for handling concurrency but I could not found the same for iOS client SDK.
Can anyone please suggest or help how to handle concurrency in iOS client SDK.
Here is the old Mobile Services page for handling conflicts with the iOS SDK. The setup for offline sync with the iOS SDK hasn't changed since then.
1) Set up an MSSyncContextDelegate and pass it to the MSSyncContext constructor when you create it.
2) Implement tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion in your delegate. After executing the operation, check for an MSErrorPreconditionFailed error code and decide what to do from there based on your app's needs.
- (void)tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion
{
[operation executeWithCompletion:^(NSDictionary *item, NSError *error) {
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
if (error.code == MSErrorPreconditionFailed) {
QSUIAlertViewWithBlock *alert = [[QSUIAlertViewWithBlock alloc] initWithCallback:^(NSInteger buttonIndex) {
if (buttonIndex == 1) { // Client
NSMutableDictionary *adjustedItem = [operation.item mutableCopy];
[adjustedItem setValue:[serverItem objectForKey:MSSystemColumnVersion] forKey:MSSystemColumnVersion];
operation.item = adjustedItem;
[self doOperation:operation complete:completion];
return;
} else if (buttonIndex == 2) { // Server
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
completion(serverItem, nil);
} else { // Cancel
[operation cancelPush];
completion(nil, error);
}
}];
NSString *message = [NSString stringWithFormat:#"Client value: %#\nServer value: %#", operation.item[#"text"], serverItem[#"text"]];
[alert showAlertWithTitle:#"Server Conflict"
message:message
cancelButtonTitle:#"Cancel"
otherButtonTitles:[NSArray arrayWithObjects:#"Use Client", #"Use Server", nil]];
} else {
completion(item, error);
}
}];
}
A part of code (I didn't write) is shown as deprecated in my Xcode project, here's the code block:
#pragma mark - Report Achievement Progress
static int reportAchievement(struct lua_State *state) {
[gameCenterAddOnInstance reportAchievementAction:[NSString stringWithCString:lua_tostring(state, 1) encoding:NSUTF8StringEncoding] percentComplete:(int)lua_tointeger(state, 2)];
return 1;
}
- (void) reportAchievementAction: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier: identifier];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"Error in reporting achievements: %#", error);
}
}];
}
}
According to Xcode, the depreciated part is:
reportAchievementWithCompletionHandler
Xcode suggests to use:
reportAchievements:WithCompletionHandler:
Instead. But, not being familiar with objective C, I wouldn't know where to start.
How to implement to new function?
Try this
[GKAchievement reportAchievements:#[achievement] withCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"Error in reporting achievements: %#", error);
}
}];
Apple replaced the instance method - reportAchievementWithCompletionHandler: with the class method + reportAchievements:withCompletionHandler:. This allows you to report multiple achievements at once without having to call the instance method on every achievement object.
#[achievement] is shorthand for [NSArray arrayWithObjects:achievement, nil].
I have been playing with icloud in the ios 8 beta, and the CloudKitAtlasAnIntroductiontoCloudKit sample project has been very helpful.
https://developer.apple.com/library/prerelease/ios/samplecode/CloudAtlas/Introduction/Intro.html
But I wanted to use the CKDiscoverAllContactsOperation class and I cannot find any sample code for it anywhere at all and the online documentation is not very helpful.
https://developer.apple.com/library/prerelease/ios/documentation/CloudKit/Reference/CKDiscoverAllContactsOperation_class/index.html
If anyone has managed to successfully use CKDiscoverAllContactsOperation could you please help point me in the right direction or show a working example of how it should be called?
I have tried this to see if I could even get an response from iCloud but nothing:
- (void)queryForRecordsOtherUsersInAddressBookcompletionHandler:(void (^)(NSArray *records))completionHandler {
CKDiscoverAllContactsOperation *discoverAllContactsOperation= [[CKDiscoverAllContactsOperation alloc] init];
[discoverAllContactsOperation setContainer:_container];
NSMutableArray *results = [[NSMutableArray alloc] init];
discoverAllContactsOperation.discoverAllContactsCompletionBlock = ^(NSArray *userInfos, NSError *operationError) {
[results addObjectsFromArray:userInfos];
};
discoverAllContactsOperation.discoverAllContactsCompletionBlock=^(NSArray *userInfos, NSError *operationError){
if (operationError) {
// In your app, handle this error with such perfection that your users will never realize an error occurred.
NSLog(#"An error occured in %#: %#", NSStringFromSelector(_cmd), operationError);
abort();
} else {
dispatch_async(dispatch_get_main_queue(), ^(void){
completionHandler(results);
});
}
};
}
and calling with this...
[self.cloudManager queryForRecordsOtherUsersInAddressBookcompletionHandler:^(NSArray *records ) {
if (records.count==0){
NSLog(#"Login name not found");
return;
}
//self.results= records;
//_loggedInRecord = self.results[0];
//NSLog(#"%#,%#",_loggedInRecord[#"lastName"],_loggedInRecord[#"firstName"]);
// [self performSegueWithIdentifier:#"loggedInSegue" sender:self ];
}];
I know the code shouldn't really do anything. Again I was just looking for a response from iCloud.
Here is what I am using. self.container is a CKContainer set with [CKContainer defaultContainer] in the init.
-(void)queryForAllUsers: (void (^)(NSArray *records))completionHandler {
CKDiscoverAllContactsOperation *op = [[CKDiscoverAllContactsOperation alloc] init];
[op setUsesBackgroundSession:YES];
op.queuePriority = NSOperationQueuePriorityNormal;
[op setDiscoverAllContactsCompletionBlock:^(NSArray *userInfos, NSError *error) {
if (error) {
NSLog(#"An error occured in %#: %#", NSStringFromSelector(_cmd), error);
//abort();
} else {
// NSLog(#"Number of records in userInfos is: %ld", (unsigned long)[userInfos count]);
dispatch_async(dispatch_get_main_queue(), ^(void){
completionHandler(userInfos);
});
}
}];
[self.container addOperation:op];
}
Before you can use the CKDiscoverAllContactsOperation operation, you first need to request for permission.
Pls use the method requestApplicationPermission:completion:
func discoverAllContacts() {
let container = CKContainer.defaultContainer()
//Request for user permission
container.requestApplicationPermission([.UserDiscoverability]) { [weak self] status, error in
switch status {
case .Granted where error == nil:
let operation = self?.discoverAllContactsOperation { usersInfo in
//do something here
}
if let operationExists = operation {
//Assuming there is a NSOperationQueue property called operationQueue
self?.operationQueue.addOperation(operationExists)
}
default:
break
}
}
}
func discoverAllContactsOperation(completionHandler: ([CKDiscoveredUserInfo]?) -> ()) -> NSOperation {
let operation = CKDiscoverAllContactsOperation()
operation.discoverAllContactsCompletionBlock = { usersInfo, error in
if error == nil {
print("Discoverd all contacts = \(usersInfo)")
completionHandler(usersInfo)
}
else {
print("Discoverd all contacts error = \(error)")
completionHandler(nil)
}
}
return operation
}