iOS開(kāi)發(fā)實(shí)戰(zhàn)-上架AppStore 通過(guò)內(nèi)購(gòu)和廣告獲得收益

寫(xiě)在前前面
弄了下個(gè)人站...防止內(nèi)容再次被鎖定...所有東西都在這里面
welcome~
個(gè)人博客

寫(xiě)在前面

由于一些原因需要離職,準(zhǔn)備重回大上海

忽然發(fā)現(xiàn)手頭上也沒(méi)什么獨(dú)立App,那就隨便寫(xiě)個(gè)放到AppStore上吧,湊個(gè)數(shù)吧。哈哈哈。

這個(gè)App是無(wú)聊找配色的時(shí)候看到的一套圖

原設(shè)計(jì)圖.png

正好春節(jié)在家沒(méi)什么特別的事,編碼用了半天左右吧,數(shù)據(jù)錄入倒是也用了半天,于是就變成了這樣。

ios版.png
自定義.png
收藏.png

上架的時(shí)候再做點(diǎn)效果圖配點(diǎn)文字 就搞定了。
不得不說(shuō) 我是白天提交的,到晚上就Review了
立馬就通過(guò)了變 ready for sale了。。。

e-mail

可能是App太過(guò)于簡(jiǎn)單了。也太好過(guò)審了。。。

廣告版集成了google的Admob (需要搭梯子)不過(guò)測(cè)試發(fā)現(xiàn)模擬器能正常顯示真機(jī)加了設(shè)備id也不能顯示,經(jīng)??占虞d。。
最近申請(qǐng)了騰訊的廣告 廣點(diǎn)通 提交了新的版本。就是注冊(cè)審核需要過(guò)個(gè)一兩天,關(guān)聯(lián)個(gè)APP要個(gè)一兩天。不過(guò)效果還是有的。
2.6提交的 ,今天(2.7)正式過(guò)審,就有收益了,估計(jì)都是自己和apple測(cè)試的時(shí)候展示的。

來(lái)??了

大家可能也看到了,這是個(gè)很簡(jiǎn)單的App,無(wú)非就是幾個(gè)列表展示下分類的顏色和收藏的顏色,擔(dān)心功能太單一,所以又添加了自定義色。下面我們來(lái)講 項(xiàng)目 Demo吧。

效果

效果

分析

感覺(jué)都沒(méi)什么好分析的了 ,就是個(gè)tableview自定義cell就行了 這里我直接用xib設(shè)置約束了

自定義cell

每個(gè)色塊有3個(gè)btn btn的顏色都是從plist中讀取,所以手工錄入還是挺耗時(shí)間的。

plist數(shù)據(jù)樣板

自定義顏色方面 直接獲取Touches的值做下計(jì)算

代碼部分

這里就貼一個(gè)自定義顏色部分。通過(guò)block回調(diào)選擇顏色的RGB值

#import <UIKit/UIKit.h>

@interface WSColorImageView : UIImageView
@property (copy, nonatomic) void(^currentColorBlock)(UIColor *color,NSString *rgbStr);
@end

#import "WSColorImageView.h"

@interface WSColorImageView()
@property (nonatomic,copy)NSString *rgbStr;

@end
@implementation WSColorImageView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.width)];
    if (self) {
        
        self.image = [UIImage imageNamed:@"palette"];
        self.userInteractionEnabled = YES;
        self.layer.cornerRadius = frame.size.width/2;
        self.layer.masksToBounds = YES;
        
    }
    return self;
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    
    UITouch *touch = [touches anyObject];
    CGPoint pointL = [touch locationInView:self];
    
    if (pow(pointL.x - self.bounds.size.width/2, 2)+pow(pointL.y-self.bounds.size.width/2, 2) <= pow(self.bounds.size.width/2, 2)) {
        
        UIColor *color = [self colorAtPixel:pointL];
        if (self.currentColorBlock) {
            
            self.currentColorBlock(color,self.rgbStr);
        }
    }
}


- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    
    UITouch *touch = [touches anyObject];
    CGPoint pointL = [touch locationInView:self];
    
    if (pow(pointL.x - self.bounds.size.width/2, 2)+pow(pointL.y-self.bounds.size.width/2, 2) <= pow(self.bounds.size.width/2, 2)) {
        
        UIColor *color = [self colorAtPixel:pointL];
        
        if (self.currentColorBlock) {
            
            self.currentColorBlock(color,self.rgbStr);
        }
    }
}



- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint pointL = [touch locationInView:self];
    
    if (pow(pointL.x - self.bounds.size.width/2, 2)+pow(pointL.y-self.bounds.size.width/2, 2) <= pow(self.bounds.size.width/2, 2)) {
        
        UIColor *color = [self colorAtPixel:pointL];
        
        if (self.currentColorBlock) {
            
            self.currentColorBlock(color,self.rgbStr);
        }
    }
}



//獲取圖片某一點(diǎn)的顏色
- (UIColor *)colorAtPixel:(CGPoint)point {
    if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, self.image.size.width, self.image.size.height), point)) {
        return nil;
    }
    
    NSInteger pointX = trunc(point.x);
    NSInteger pointY = trunc(point.y);
    CGImageRef cgImage = self.image.CGImage;
    NSUInteger width = self.image.size.width;
    NSUInteger height = self.image.size.height;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int bytesPerPixel = 4;
    int bytesPerRow = bytesPerPixel * 1;
    NSUInteger bitsPerComponent = 8;
    unsigned char pixelData[4] = { 0, 0, 0, 0 };
    CGContextRef context = CGBitmapContextCreate(pixelData,
                                                 1,
                                                 1,
                                                 bitsPerComponent,
                                                 bytesPerRow,
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast |     kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    
    CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
    CGContextRelease(context);
    
    CGFloat red   = (CGFloat)pixelData[0] / 255.0f;
    CGFloat green = (CGFloat)pixelData[1] / 255.0f;
    CGFloat blue  = (CGFloat)pixelData[2] / 255.0f;
    CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
    
    NSLog(@"%f***%f***%f***%f",red,green,blue,alpha);
    NSLog(@"%d,%d,%d",pixelData[0],pixelData[1],pixelData[2]);
    self.rgbStr = [NSString stringWithFormat:@"%d,%d,%d",pixelData[0],pixelData[1],pixelData[2]];
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

- (void)setImage:(UIImage *)image {
    UIImage *temp = [self imageForResizeWithImage:image resize:CGSizeMake(self.frame.size.width, self.frame.size.width)];
    [super setImage:temp];
}

- (UIImage *)imageForResizeWithImage:(UIImage *)picture resize:(CGSize)resize {
    CGSize imageSize = resize; //CGSizeMake(25, 25)
    UIGraphicsBeginImageContextWithOptions(imageSize, NO,0.0);
    CGRect imageRect = CGRectMake(0.0, 0.0, imageSize.width, imageSize.height);
    [picture drawInRect:imageRect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    return image;
}
@end

補(bǔ)充

給免費(fèi)版添加了內(nèi)購(gòu)去廣告功能。
使用的是本地?cái)?shù)據(jù)庫(kù),自定義tableview的footview。
未購(gòu)買(mǎi)標(biāo)識(shí)為0,廣告位的frame高設(shè)為44;
購(gòu)買(mǎi)成功就將標(biāo)識(shí)設(shè)為1,廣告位frame高設(shè)為0;
都是tableview直接reload。

這里再給出內(nèi)購(gòu)的代碼。

注意:設(shè)置成訂閱類商品(非消耗)一定要添加恢復(fù)購(gòu)買(mǎi)的代碼 不然審核會(huì)被拒

#import <StoreKit/StoreKit.h>
@interface ColorFavTableViewController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
#pragma mark - 內(nèi)購(gòu)
- (IBAction)clickPhures:(id)sender {

//    [[CoreDataOperations sharedInstance] buyNoAds];
//    [self.tableView reloadData];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"花費(fèi)6元購(gòu)買(mǎi)去廣告" preferredStyle:UIAlertControllerStyleActionSheet];
    [alertController addAction:[UIAlertAction actionWithTitle:@"確定購(gòu)買(mǎi)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        

        NSString *product = @"123";
        _currentProId = product;
        if([SKPaymentQueue canMakePayments]){
            [self requestProductData:product];
        }else{
            NSLog(@"不允許程序內(nèi)付費(fèi)");
        }
    }]];
    
    [alertController addAction:[UIAlertAction actionWithTitle:@"已購(gòu)買(mǎi)直接去廣告" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        
        [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
    }]];
    
    [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
    [self presentViewController:alertController animated:YES completion:nil];
    
}


//請(qǐng)求商品
- (void)requestProductData:(NSString *)type{
    NSLog(@"-------------請(qǐng)求對(duì)應(yīng)的產(chǎn)品信息----------------");
    
    
    NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
    
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;
    [request start];
    
}

//收到產(chǎn)品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"--------------收到產(chǎn)品反饋消息---------------------");
    NSArray *product = response.products;
    if([product count] == 0){
        NSLog(@"--------------沒(méi)有商品------------------");
        return;
    }
    
    NSLog(@"productID:%@", response.invalidProductIdentifiers);
    NSLog(@"產(chǎn)品付費(fèi)數(shù)量:%lu",(unsigned long)[product count]);
    
    SKProduct *p = nil;
    for (SKProduct *pro in product) {
        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);
        
        if([pro.productIdentifier isEqualToString:_currentProId]){
            p = pro;
        }
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    
    NSLog(@"發(fā)送購(gòu)買(mǎi)請(qǐng)求");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

//請(qǐng)求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"------------------錯(cuò)誤-----------------:%@", error);
}

- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"------------反饋信息結(jié)束-----------------");
}
//沙盒測(cè)試環(huán)境驗(yàn)證
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式環(huán)境驗(yàn)證
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
 *  驗(yàn)證購(gòu)買(mǎi),避免越獄軟件模擬蘋(píng)果請(qǐng)求達(dá)到非法購(gòu)買(mǎi)問(wèn)題
 *
 */
-(void)verifyPurchaseWithPaymentTransaction{
    //從沙盒中獲取交易憑證并且拼接成請(qǐng)求體數(shù)據(jù)
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
    
    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//轉(zhuǎn)化為base64字符串
    
    NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接請(qǐng)求數(shù)據(jù)
    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    //創(chuàng)建請(qǐng)求到蘋(píng)果官方進(jìn)行購(gòu)買(mǎi)驗(yàn)證
    NSURL *url=[NSURL URLWithString:AppStore];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    requestM.HTTPMethod=@"POST";
    //創(chuàng)建連接并發(fā)送同步請(qǐng)求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
    if (error) {
        NSLog(@"驗(yàn)證購(gòu)買(mǎi)過(guò)程中發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"%@",dic);
    if([dic[@"status"] intValue]==0){
        NSLog(@"購(gòu)買(mǎi)成功!");
        [[CoreDataOperations sharedInstance] buyNoAds];
        [self.tableView reloadData];

        NSDictionary *dicReceipt= dic[@"receipt"];
        NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];
        NSString *productIdentifier= dicInApp[@"product_id"];//讀取產(chǎn)品標(biāo)識(shí)
        //如果是消耗品則記錄購(gòu)買(mǎi)數(shù)量,非消耗品則記錄是否購(gòu)買(mǎi)過(guò)
        NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
        if ([productIdentifier isEqualToString:@"123"]) {
            int purchasedCount=[defaults integerForKey:productIdentifier];//已購(gòu)買(mǎi)數(shù)量
            [[NSUserDefaults standardUserDefaults] setInteger:(purchasedCount+1) forKey:productIdentifier];
        }else{
            [defaults setBool:YES forKey:productIdentifier];
        }
        //在此處對(duì)購(gòu)買(mǎi)記錄進(jìn)行存儲(chǔ),可以存儲(chǔ)到開(kāi)發(fā)商的服務(wù)器端
    }else{
        NSLog(@"購(gòu)買(mǎi)失敗,未通過(guò)驗(yàn)證!");
    }
}
//監(jiān)聽(tīng)購(gòu)買(mǎi)結(jié)果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    
    
    for(SKPaymentTransaction *tran in transaction){
        

        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"交易完成");
                [self verifyPurchaseWithPaymentTransaction];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                [[CoreDataOperations sharedInstance] buyNoAds];
                [self.tableView reloadData];
                
            }
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加進(jìn)列表");
                
                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"已經(jīng)購(gòu)買(mǎi)過(guò)商品");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                [[CoreDataOperations sharedInstance] buyNoAds];
                [self.tableView reloadData];
            }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"交易失敗");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            default:
                break;
        }
    }
}

//交易結(jié)束
- (void)completeTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"交易結(jié)束");
    
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}


- (void)dealloc{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

Demo地址

廣告版免費(fèi),收費(fèi)版1元,有興趣的可以下來(lái)玩玩
當(dāng)然,Github公開(kāi)無(wú)廣告版的源碼,歡迎點(diǎn)贊加星

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容