2016年5月22日星期日

APP内购流程

APP内购流程

大致的业务逻辑是这样的
1. 程序通过bundle存储的plist文件得到产品标识符的列表。(从苹果网站后台下载产品列表,这个必须有)
2. 程序向App Store发送请求,得到产品的信息。
3. App Store返回产品信息。
4. 程序把返回的产品信息显示给用户(Appstore界面)
5. 用户选择某个产品
6. 程序向App Store发送支付请求
7. App Store处理支付请求并返回交易完成信息。
8. App获取信息并提供内容给用户。
    整个流程都是安全的,都是StoreKitAppStore通信,需要的做的就是设置和回调接受结果就好
.流程

首先登录到apple开发者中心点击进入我的App”. - >功能

左边第一项App内购项目.新建一个内购项目

选取您要创建的 App 内购买类型。如果缺少某个类型,请确保您已同意最新的付费应用程序协议。若要执行同意此协议操作,具有法务职能的用户必须前往协议、税务和银行业务。确保您在前往“协议、税务和银行业务”页面前已同意开发人员计划许可协议。您还应该确保您的 App 不受 App 内购买项目的欺诈,请查看 App 内购买收据验证文件。

App内购项目主要分为以下几项
1.消耗型项目
对于消耗型 App 内购买项目,用户每次下载时都必须进行购买。一次性服务通常属于消耗型项目,例如钓鱼 App 中的鱼饵。
2.非消耗型项目
对于非消耗型 App 内购买项目,用户仅需要购买一次。不会过期或随使用而减少的服务通常为非消耗型项目,例如游戏 App 的新跑道。
3.自动续订订阅
通过自动续订订阅,用户可以购买指定时间期限内的更新和动态内容。除非用户取消选择,否则订阅(例如杂志订阅等)会自动续订。
4.免费订阅
免费订阅是开发人员在“报刊杂志”中推广其内容的绝佳方式。用户注册免费订阅后,此订阅内容在与该用户 Apple ID 相关联的所有设备上可用。免费订阅不会过期,并且仅能在位于“报刊杂志”类别中的 App 中提供。
5.非续订订阅
非续订订阅允许有时限性的营销服务。对于 App 内购买项目中的限时访问内容,就需使用非续订订阅。例如,导航 App 中语音导航功能的一周订阅,或者年度订阅已存档的视频或音频的在线目录。


建立产品数据

*在提交 App 内购买项目以供审核前,您必须先上传屏幕快照。此屏幕快照仅用于审核目的,不会显示在 App Store 中。屏幕快照必须至少 312x390 像素,并且至少为 72 DPI

保存之后可以看到生成的信息


*协议、税务和银行业务,里面的Contact InfoBank InfoTax Info这三个信息填完整(少一个都不会拿到商品信息)
.代码
1. 工程中导入 StoreKit.Framework 框架
   在需要支付的vc #import<StoreKit/StoreKit.h>
2. - (void)viewDidLoad里添加购买监听
   [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

3. 检测是否允许内购
   if([SKPaymentQueue canMakePayments]){
            [selfrequestProductData:productID];       
   }else{
        NSLog(@"不允许程序内付费");       

   }

4.请求商品信息
   - (void)requestProductData:(NSString*)type{

NSArray*product = [[NSArrayalloc] initWithObjects:type,nil];

NSSet*nsset = [NSSetsetWithArray:product];

SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];

request.delegate=self;    

[request start];

}
成功之后收到产品返回信息
-(void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse *)response{
NSArray*product = response.products;
if([product count] ==0){
NSLog(@"没有商品");
return;
}
SKPayment * payment = [SKPayment paymentWithProduct:p];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
失败执行方法
- (void)request:(SKRequest*)request didFailWithError:(NSError*)error {
NSLog(@"商品信息请求错误:%@", error);
}
- (void)requestDidFinish:(SKRequest*)request {
NSLog(@"请求结束");
}

5.监听购买结果
-(void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray *)transaction {

for(SKPaymentTransaction *tranintransaction){

switch(tran.transactionState) {

caseSKPaymentTransactionStatePurchased:

NSLog(@"交易完成");

break;

caseSKPaymentTransactionStatePurchasing:

NSLog(@"商品添加进列表");

break;

caseSKPaymentTransactionStateRestored:

NSLog(@"已经购买过商品");

break;

caseSKPaymentTransactionStateFailed:

NSLog(@"交易失败");

break;

default:

[SVProgressHUDdismiss];

break;

}

*因为是去请求苹果的服务器,所以请求时间会稍微有点长

.测试

这个测试我也是挺呵呵的.构建测试版本到测试环境进行测试……..


demo实例(非官方提供)

其他博客整理仅供参考

.其他(服务端代码)
<?php 
    //服务器二次验证代码 
    function getReceiptData($receipt, $isSandbox = false)    
    {    
        if ($isSandbox) {    
            $endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';    
        }    
        else {    
            $endpoint = 'https://buy.itunes.apple.com/verifyReceipt';    
        }    

        $postData = json_encode(    
            array('receipt-data' => $receipt)    
        );    

        $ch = curl_init($endpoint);    
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);    
        curl_setopt($ch, CURLOPT_POST, true);    
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);    
       curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);  //这两行一定要加,不加会报SSL 错误 
        curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);  


        $response = curl_exec($ch);    
        $errno    = curl_errno($ch);    
        $errmsg   = curl_error($ch);    
        curl_close($ch);    
    //判断时候出错,抛出异常 
        if ($errno != 0) {    
            throw new Exception($errmsg, $errno);    
        }    

        $data = json_decode($response);    
    //判断返回的数据是否是对象 
        if (!is_object($data)) {    
            throw new Exception('Invalid response data');    
        }    
    //判断购买时候成功 
        if (!isset($data->status) || $data->status != 0) {    
            throw new Exception('Invalid receipt');    
        }    

    //返回产品的信息            
        return array(    
            'quantity'       =>  $data->receipt->quantity,    
            'product_id'     =>  $data->receipt->product_id,    
            'transaction_id' =>  $data->receipt->transaction_id,    
            'purchase_date'  =>  $data->receipt->purchase_date,    
            'app_item_id'    =>  $data->receipt->app_item_id,    
            'bid'            =>  $data->receipt->bid,    
            'bvrs'           =>  $data->receipt->bvrs    
        );    
    }    

    //获取 App 发送过来的数据,设置时候是沙盒状态 
        $receipt   = $_GET['data'];    
        $isSandbox = true;    
    //开始执行验证 
    try 
     { 
         $info = getReceiptData($receipt, $isSandbox);    
         // 通过product_id 来判断是下载哪个资源 
         switch($info['product_id']){ 
            case 'com.application.xxxxx.xxxx': 
                Header("Location:xxxx.zip"); 
            break;            
        } 
     } 
    //捕获异常 
    catch(Exception $e) 
    { 
        echo 'Message: ' .$e->getMessage(); 
    } 

?>

2016年4月18日星期一

关于iOS开发中info.plist文件的解读



1. Localiztion native development region --- CFBundleDevelopmentRegion 本地化相关,如果用户所在地没有相应的语言资源,则用这个key的value来作为默认.

2. Bundle display name --- CFBundleDisplayName 设置程序安装后显示的名称。应用程序名称限制在10-12个字符,如果超出,将被显示缩写名称。

3. Executaule file -- CFBundleExecutable 程序安装包的名称

4. Icon file --- CFBundleIconFile 应用程序图标名称,一般为icon.png

5. Bundle identifier --- CFBundleIdentifier 这个字段很重要,程序的唯一标识字符串,该字符串的value值习惯命名格式为: com.yourcompany.yourapp,它是每一个应用的身份证书,这个为应用程序在iphone developer program portal web站点上设置的唯一标识符。(就是你安装证书的时候,需要把这里对应修改).

6. InfoDictionary version --- CFBundleInfoDictionaryVersion Info.plist格式的版本信息

7. Bundle OS Type code -- 关键字指定了束的类型,类似于Mac OS 9的文件类型代码。该关键字的值包含一个四个字母长的代码。应用程序的代码是‘APPL’;框架的代码是‘FMWK’;可装载束的代码是‘BND’。如果您需要,您也可以为可装载束选择其他特殊的类型代码。

8. Bundle versions string, short ---指定了束的版本号。一般包含该束的主、次版本号。这个字符串的格式通常是“n.n.n”(n表示某个数字)。第一个数字是束的主要版本号,另两个是次要版本号。该关键字的值会被显示在Cocoa应用程序的关于对话框中。该关键字不同于CFBundleVersion,它指定了一个特殊的创建号。而CFBundleShortVersionString的值描述了一种更加正式的并且不随每一次创建而改变的版本号。

9. Application require iPhone environment -- LSRequiresIPhoneOS:用于指示程序包是否只能运行在iPhone OS 系统上。Xcode自动加入这个键,并将它的值设置为true。一般不需要更改这个值.

10. Launch screen interface file base name:欢迎界面的文件名称

11. Main storyboard file base name:默认情况下程序的主入口

12. Required device capabilities 当提交程序到app store时,3.0及更高版本的应用程序不再直接说明使用哪种设备,而是使用info.plist文件来确定需要哪些设备功能。iTunes通过这个所需功能的列表来确定一个应用程序能否下载到一个指定的设备并在该设备上正常运行。

13. Supported interface orientations:设置程序默认支持的方向

2016年4月6日星期三

2016年2月28日星期日

iOS开发跳到系统设置界面

定位服务

定位服务有很多app都有,如果用户关闭了定位服务.我们要在设置里打开.代码如下

//定位服务设置界面
NSURL *url = [NSURL URLWithString:@"prefs:root=LOCATION_SERVICES"];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
    [[UIApplication sharedApplication] openURL:url];
}

2016年2月22日星期一

Xcode中SVN提交.a文件问题

1. 打开终端,  在命令行中输入: vi ~/.subversion/config  来打开配置文件.
2. 然后, 在[miscellany]项找到这个串:  
# global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo
#   *.rej *~ #*# .#* .*.swp .DS_Store

这里的意思是, SVN在提交时自动忽略以这些后缀的文件, 那么我们要去掉*.a这一项, 则将配置文件改为
global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]*  *.pyc *.pyo *.rej *~ #*# .#* .*.swp .DS_Store
保存退出. 就可以了. 你可以根据自己的需要修改其他的后缀名.