In App Purchases(IAP 应用程序內购买): 完全攻略

时间:2022-02-01 13:56:14

原文: http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/

参考:
http://www.cocoachina.com/bbs/read.php?tid-11357.html


新:
http://www.cocoachina.com/gamedev/misc/2012/0409/4129.html
   
demo


第一印象觉得In-App Purchase(简称IAP)非常简单。Apple提供的大量文档应该让开发者很快熟悉地熟悉。那麽,为什麽在你的应用中集成IAP特性就如此令人生厌呢?

这是因为在开发过程中不可避免会出现一些错误。而但这些错误发生的时候,你就抓瞎了。虽然Apple提供了有关IAP的大量文档,但他们并未提及集成IAP的详细步骤。而且对StoreKit集成过程中出现的问题也没有一个核对清单。另外对于为什麽诸如产品ID非法之类的问题也没有提供NSError之类的对象来告诉你原因。

在试用了各种可能的解决方桉后,你只能身心疲惫,彷徨无助。

为了提高你的效率和减少你的痛苦,我觉定利用此文来介绍一下实现IAP的详细步骤。本文很详细,有点长。甚至可能太长了,但不像Apple的文档,它提供了为实现IAP的每一个步骤。

废话少说,我们直入主题吧。

概况


IAP能正常工作的秘诀:分成两个步骤:

创建及提取产品描述


购买产品


第一个步骤是你可能遇到问题的部分。一旦你在代码中成功地获取了产品描述,编写购买产品的代码不过是小菜一碟。

我们先看看步骤1。

创建及提取产品描述


下面是有关创建产品及提取其描述的非常粗略的步骤:

创建唯一的App ID


生成及安装新的provisioning profile文件


在Xcode中更新 bundle ID 及 code signing profile


如果还没做的话,请在iTunes Connect中提交有关你程序的 metadata


如果还没做的话,请在iTunes Connect中提交你程序的二进制码


为IAP添加新产品


编写提取产品描述的代码


等待几小时


提取产品描述的代码非常简单,但其他步骤则很容易错。

注意: 为提取产品描述,你并不需要在iTunes Connect中创建IAP测试用户。

1. 创建唯一的App ID


为支持IAP,你的App ID不能包括通配符(“*”)。为确定你的App Id是否包括通配符,请登录
http://developer.apple.com/iphone
,在 iPhone Developer Program Portal中选择左边菜单中的 “App IDs”检查你的 App ID。

下面是一个唯一的App ID:

7DW89RZKLY.com.runmonster.runmonsterfree

下面不是一个唯一的 App ID:

7DW89RZKLY.com.runmonster.*

如果你还没有一个唯一的App ID,按如下步骤创建一个:

在developer portal中的 App IDs 部分,选择“New App ID”


填写下列信息:


Display name(显示名): 选取一个不同的App ID的名称。你不能编辑或删除旧的App ID,所以你必须为你的App ID提供一个新名称以避免溷淆。


Prefix(前缀): 生成一个新的前缀,或者如果你的程序是通过Keychain Services API分享数据的系列程序中之一的话,则选用已存在的前缀。


Suffix(后缀): com.companyname.appname (这是通用格式 – 注意没有使用通配符)。


按 “Save”


按 App ID旁的“Configure” 链接


选取 “Enable In App Purchase”选择框


按“Done”


2. 创建一个新的Provisioning Profile文件


在创建了新的App ID后,你需要生成一个指向这个App ID的新provisioning profile。

下面就是令人痛苦的生成和安装新provisioning profile的详细步骤:

在 iPhone Developer Portal中, 选择左边的Provisioning部分


确保你处于Development 标籤下, 按下右上角的 “New Profile”


填入所需信息并指向你刚创建的唯一的App ID


如果你在Actions条目下看到 “Pending”,那麽请按下“Development”标籤标题进行刷新


点击 “Download” 下载新的profile文件


将profile文件拖入到Dock中Xcode图标上进行安装


如果你想在硬盘上保存provisioning profile,那麽你可以按如下步骤手工安装profile:


在Xcode中, 选择 Window > Organizer


选择左边 “Provisioning Profiles” 分类


Ctrl-按下profile > Reveal in Finder


将新profile拖入到 profile Finder 窗口


3. 更新Xcode 设置


在Xcode中安装了 profile 文件后,你需要对使用此provisiong profile的项目进行一些编辑工作:

编辑项目 .plist 文件使其 Bundle ID 与 App ID 匹配。忽略ID开始部分的字母数字序列。例如,在Developer Portal中你的App ID为“7DW89RZKLY.com.runmonster.runmonsterfree”,那麽在Bundle ID中你只需输入“com.runmonster.runmonsterfree” 。


编辑项目的 target 信息以使用新的provisioning profile:


选取 Project > Edit Active Target


选取顶部“Build” 标籤


选取需要的 configuration (通常为 Debug)


在Code Signing Identity中选择新的provisioning profile


在Code Signing Identity之下的行中(可能名为 Any iPhone OS Device)选择新的provisioning profile


4. 添加你的应用程序


如果你的程序已经发表到App Store了,那麽可以略过此步骤。

在你将产品添加到 iTunes Connect之前,你必须添加此产品所需的程序。如果你的程序还没有100%完成也无需担心,你可以先提交具有部分数据的程序,最后再提交真实的程序。

注意: 只有 SKU 和 version(版本)部分是以后不可修改的

登录到 
http://developer.apple.com/iphone


点击右边链接进入 iTunes Connect


注意:你必须先登录到developer.apple.com,否则会有不测发生(译者注:具体是什麽不测我也不太清楚,胆大的请自己试一下)


在 iTunes Connect主页点击 “Manage Your Applications”


在右上角点击“Create New Application”


填写程序所需的一切信息。当要求程序二进制码时,请选择稍后上传选项。


5. 提交程序二进制码


Apple的文档中没有任何地方提及详情,但它却是必须的步骤。要成功测IAP功能,你必须提交程序的二进制码。即使你的程序还没有100%完成,你仍然需要提交二进制码。然而,你也可以立即摈弃你的二进制码,使其不会进入审核阶段。

下面这些步骤非常关键,我可是因为少做了某些步骤而度过了一段非常痛苦的时间:

生成App Store发佈版程序


如果你不知怎麽做,请在 iPhone Developer Portal 中点击左方的 Distribution标籤,并选择 “Prepare App” 标籤。然后,根据蓝色链接的指示:


获取iPhone发行许可证


创建并下载在App Store发行所需的iPhone Distribution Provisioning Profile


在Xcode中生成程序的发行版


在iTunes Connect中进入程序页


选择 “Upload Binary”


上传.zip压缩程序


如果你的程序还没有100%完成以进行审核,那麽请点击iTunes Connect中你程序首页中的 “Reject Binary”链接。程序的状态应该更新为 “Developer Rejected”.


不用担心,由于程序的状态是“Developer Rejected”,Apple是不会对其进行审核的。你可以在任何时候提交程序的新版本并使其状态为“Developer Rejected”,这不会对以后程序正式提交的等待时间有任何影响。

6. 添加产品


完成了以上所有步骤后,我们最终可以向iTunes Connect中添加产品了。

确保登录到 
http://developer.apple.com/iphone


进入 iTunes Connect 主页


点击“Manage Your Applications”


点击刚建好的程序 点击view details


点击 “Manage in-App Purchases” 链接


点击 “Create New”


填写下列产品信息:


Reference Name(参考名称): 产品的通用名称。比如,我使用的是 “Pro Upgrade”。此名称是不允许进行编辑的,它不会显示于App Store中。


Product ID(产品ID): 你产品的唯一id。通常格式是 com.company.appname.product,但它可以说任何形式。它并不要求以程序的App ID作为前缀。


Type(类型): 有三种选择


Non-consumable(非消耗品): 仅需付费一次 (例如你希望将出现从免费版升级为专业版)


Consumable(消耗品): 每次下载都需要付费


Subscription(预订): 循环反覆


Price Tier(价格等级): 产品价格。参见不同等级的价格列表。


Cleared for Sale(等待销售): 一定要选取此项,否则的话,测试时会发生非法产品ID的错误。


Language to Add(增加的语言): 选一项。下列两项将出现:


Displayed Name(显示名称): 用户看到的产品名称。比如我选择 “Upgrade to Pro”。


Description(描述): 对产品进行描述。此处输入的文本将与Displayed Name 及 Price 一起在你代码中提取 SKProduct时出现。


Screenshot(截屏): 展示你产品的截屏。儘管屏幕上会显示“提交截屏会触发产品审核过程”之类的文字(个人拙见,这是非常糟糕的设计),你还是可以安全地提交截屏而不会使产品进入审核过程。存储后,选择“Submit with app binary” (随程序二进制码一起提交)选项。是产品与程序二进制绑定在一起,所以在你最后正式提交100%完成的程序二进制码时,产品也会随之提交。


点击 “Save”


最后一定不要忘了回到view details  编辑In-App Purchases


选择刚刚添加的iap版本


7. 编写代码


下面我们开始编写代码对刚加入到iTunes Connect中的产品信息进行提取。我访问产品数据,我们需要使用 StoreKit framework。

注意: StoreKit 无法在模拟器上工作。你必须在真机上进行测试。

1.添加 StoreKit framework 到你的项目中。


2.添加SKProduct引用到你的 .h 文件中:

 

复制代码

  1. // InAppPurchaseManager.h
  2. #import <StoreKit/StoreKit.h>
  3. #define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification"
  4. @interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate>
  5. {
  6. SKProduct *proUpgradeProduct;
  7. SKProductsRequest *productsRequest;
  8. }

注意: InAppPurchaseManager 是一个单例类,它处理程序中所有IAP任务。它是本文中的示例程序。

3.产品请求,并在相应.m文件中实现代理协议:

 

复制代码

  1. // InAppPurchaseManager.m
  2. - (void)requestProUpgradeProductData
  3. {
  4. NSSet *productIdentifiers = [NSSet setWithObject:@"com.runmonster.runmonsterfree.upgradetopro" ];
  5. productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
  6. productsRequest.delegate = self;
  7. [productsRequest start];
  8. // we will release the request object in the delegate callback
  9. }
  10. #pragma mark -
  11. #pragma mark SKProductsRequestDelegate methods
  12. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
  13. {
  14. NSArray *products = response.products;
  15. proUpgradeProduct = [products count] == 1 ? [[products firstObject] retain] : nil;
  16. if (proUpgradeProduct)
  17. {
  18. NSLog(@"Product title: %@" , proUpgradeProduct.localizedTitle);
  19. NSLog(@"Product description: %@" , proUpgradeProduct.localizedDescription);
  20. NSLog(@"Product price: %@" , proUpgradeProduct.price);
  21. NSLog(@"Product id: %@" , proUpgradeProduct.productIdentifier);
  22. }
  23. for (NSString *invalidProductId in response.invalidProductIdentifiers)
  24. {
  25. NSLog(@"Invalid product id: %@" , invalidProductId);
  26. }
  27. // finally release the reqest we alloc/init’ed in requestProUpgradeProductData
  28. [productsRequest release];
  29. [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
  30. }

上面代码有几点需要注意:

指定产品id时,你必须使用完整产品id。例如,上例中使用 “com.runmonster.runmonsterfree.upgradetopro”。仅使用 “upgradetopro” 将不会正常工作。


如果在productsRequest:didReceiveResponse:中response.products 为 nil,而你的产品id出现于 response.invalidProductIdentifers 数组中时,那麽请做好心理准备开始一场徒劳的搜索战吧。 StoreKit API没有提供任何帮助,也没有任何指示关于为什麽你的id是无效的。很可爱,不是吗?


SKProduct类提供了有关程序标题和描述的本地化版本,但是价格则没有本地化版本。下面是针对此疏忽提供的代码:

 

复制代码

  1. // SKProduct+LocalizedPrice.h
  2. #import <Foundation/Foundation.h>
  3. #import <StoreKit/StoreKit.h>
  4. @interface SKProduct (LocalizedPrice)
  5. @property (nonatomic, readonly) NSString *localizedPrice;
  6. @end
 

复制代码

  1. // SKProduct+LocalizedPrice.m
  2. #import "SKProduct+LocalizedPrice.h"
  3. @implementation SKProduct (LocalizedPrice)
  4. - (NSString *)localizedPrice
  5. {
  6. NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
  7. [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
  8. [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
  9. [numberFormatter setLocale:self.priceLocale];
  10. NSString *formattedString = [numberFormatter stringFromNumber:self.price];
  11. [numberFormatter release];
  12. return formattedString;
  13. }
  14. @end

加入上述代码,测试一下。你应该在控制台窗口中看见产品信息了。然而更大的可能是,你得到了一个无效的产品id。我下一篇文章将介绍怎样对这个问题进行调试。但是,下面的步骤8有可能是阻碍你前进的障碍。

8. 等待几小时


遵循了上述所有步骤,但是你的产品仍然是无效的?你是否两次,三次,四次不懈努力地确认你是否遵循了上面提到的每个步骤?你是否已经对网上IAP信息少得可怜而感到绝望?

那麽,你应该等待。

你的产品要进入iTunes Connect使得Apple准备好沙箱环境需要一些时间。对于我而言,我是经过了无数次产品无效错误的绝望。而在24小时后,我没有修改任何一行代码,但产品id变为有效。我认为要使产品发佈到Apple的网络系统需要几个小时的时间,但如果你有时间的话,你可以像我一样等上24个小时。

购买产品


至此你应该已经成功地获取了 SKProduct 描述。比较而言,支持购买产品相对简单些。仅需下面三个步骤:

编写代码支持事务(transaction)


在iTunes Connect中添加程序测试用户


在设备中登录你的 iTunes Store 帐号


购买测试


我们从编写支持事务所需代码开始。

1. 编写代码支持事务


首先注意:你将负责开发产品购买的用户界面。StoreKit 未提供任何与用户界面相关的元素。如果你希望你的购买用户界面与App Store一样,那麽你要自己完成。

下面所有代码都是有关事务处理的后台部分。这是一个单独的类只有一条简单的API以供外部类(比如view controller)调用进行购买。如果你找到将其集成到你程序的购买部分的方法,那麽我推荐你使用类似方桉。

首先,需要遵循 SKPaymentTransactionObserver 协议:

 

复制代码

  1. // InAppPurchaseManager.h
  2. // add a couple notifications sent out when the transaction completes
  3. #define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification"
  4. #define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification"
  5. @interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
  6. {
  7. }
  8. // public methods
  9. - (void)loadStore;
  10. - (BOOL)canMakePurchases;
  11. - (void)purchaseProUpgrade;
  12. @end

上面我们定义了两个新的notification,它们将作为购买事务的结果被发送。在上例中我们仍然使用与获取产品描述同一个InAppPurchaseManager类。

 

复制代码

  1. // InAppPurchaseManager.m
  2. #define kInAppPurchaseProUpgradeProductId @"com.runmonster.runmonsterfree.upgradetopro"
  3. #pragma -
  4. #pragma Public methods
  5. //
  6. // call this method once on startup
  7. //
  8. - (void)loadStore
  9. {
  10. // restarts any purchases if they were interrupted last time the app was open
  11. [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  12. // get the product description (defined in early sections)
  13. [self requestProUpgradeProductData];
  14. }
  15. //
  16. // call this before making a purchase
  17. //
  18. - (BOOL)canMakePurchases
  19. {
  20. return [SKPaymentQueue canMakePayments];
  21. }
  22. //
  23. // kick off the upgrade transaction
  24. //
  25. - (void)purchaseProUpgrade
  26. {
  27. SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId];
  28. [[SKPaymentQueue defaultQueue] addPayment:payment];
  29. }
  30. #pragma -
  31. #pragma Purchase helpers
  32. //
  33. // saves a record of the transaction by storing the receipt to disk
  34. //
  35. - (void)recordTransaction:(SKPaymentTransaction *)transaction
  36. {
  37. if ([transaction.payment.productIdentifier isEqualToString:kInAppPurchaseProUpgradeProductId])
  38. {
  39. // save the transaction receipt to disk
  40. [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"proUpgradeTransactionReceipt" ];
  41. [[NSUserDefaults standardUserDefaults] synchronize];
  42. }
  43. }
  44. //
  45. // enable pro features
  46. //
  47. - (void)provideContent:(NSString *)productId
  48. {
  49. if ([productId isEqualToString:kInAppPurchaseProUpgradeProductId])
  50. {
  51. // enable the pro features
  52. [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isProUpgradePurchased" ];
  53. [[NSUserDefaults standardUserDefaults] synchronize];
  54. }
  55. }
  56. //
  57. // removes the transaction from the queue and posts a notification with the transaction result
  58. //
  59. - (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
  60. {
  61. // remove the transaction from the payment queue.
  62. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  63. NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
  64. if (wasSuccessful)
  65. {
  66. // send out a notification that we’ve finished the transaction
  67. [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];
  68. }
  69. else
  70. {
  71. // send out a notification for the failed transaction
  72. [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
  73. }
  74. }
  75. //
  76. // called when the transaction was successful
  77. //
  78. - (void)completeTransaction:(SKPaymentTransaction *)transaction
  79. {
  80. [self recordTransaction:transaction];
  81. [self provideContent:transaction.payment.productIdentifier];
  82. [self finishTransaction:transaction wasSuccessful:YES];
  83. }
  84. //
  85. // called when a transaction has been restored and and successfully completed
  86. //
  87. - (void)restoreTransaction:(SKPaymentTransaction *)transaction
  88. {
  89. [self recordTransaction:transaction.originalTransaction];
  90. [self provideContent:transaction.originalTransaction.payment.productIdentifier];
  91. [self finishTransaction:transaction wasSuccessful:YES];
  92. }
  93. //
  94. // called when a transaction has failed
  95. //
  96. - (void)failedTransaction:(SKPaymentTransaction *)transaction
  97. {
  98. if (transaction.error.code != SKErrorPaymentCancelled)
  99. {
  100. // error!
  101. [self finishTransaction:transaction wasSuccessful:NO];
  102. }
  103. else
  104. {
  105. // this is fine, the user just cancelled, so don’t notify
  106. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  107. }
  108. }
  109. #pragma mark -
  110. #pragma mark SKPaymentTransactionObserver methods
  111. //
  112. // called when the transaction status is updated
  113. //
  114. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
  115. {
  116. for (SKPaymentTransaction *transaction in transactions)
  117. {
  118. switch (transaction.transactionState)
  119. {
  120. case SKPaymentTransactionStatePurchased:
  121. [self completeTransaction:transaction];
  122. break;
  123. case SKPaymentTransactionStateFailed:
  124. [self failedTransaction:transaction];
  125. break;
  126. case SKPaymentTransactionStateRestored:
  127. [self restoreTransaction:transaction];
  128. break;
  129. default:
  130. break;
  131. }
  132. }
  133. }

要测试上面的新代码,你还需要编写调用 loadStore, canMakePurchases 以及 purchaseProUpgrade 方法的代码。

有关上述代码的详细解释,请参考官方 In App Purchase Programming Guide (IAP编程指南)

上述代码有几个部分是针对我的程序的。例如,在 provideContent:中,NSUserDefaults 中的@”isProUpgradePurchased” BOOL 字段被设定为 YES。程序的其他部分将检查此BOOL值以确定是否需要启动专业版功能。如果你正好也要实现免费升级专业版的功能,那麽你可以使用同样的方法。

2. 添加测试用户


为测试上述代码,你需要在 iTunes Connect 中创建测试用户以对IAP功能进行测试。你可以使用测试帐号购买产品而不被Apple收取费用。

按以下步骤创建测试用户:

登录到 
http://developer.apple.com/iphone


进入 iTunes Connect


选择iTunes Connect首页中的 “Manage Users”


选择 “In App Purchase Test User”


选择 “Add New User”


填入用户信息. 所有信息都不必是合法的。建议使用虚假简短的email地址及简短的密码。


选择 “Save”


测试时你需要输入这些email地址和密码。

3. 在你的设备中退出登录


在进行程序购买功能测试前,你必须在你的设备中退出iTunes Store。遵循以下步骤:

打开Settings App


点击 “Store” 行


点击 “Sign Out”


4. 购买测试


现在,终于可以开始进行IAP功能的测试了。测试很简单:

运行你设备中的程序


进行购买


当程序提示输入用户名和密码时,输入参数用户的信息


如果你使用同一账户进行购买时,系统将提示你已经购买了此产品。按“Yes”就可以再次下载此产品。

总结


实现IAP功能比想象的要複杂许多。我可是经过无数痛苦的经历才完成我的程序。希望能够帮助其他开发者减轻他们的痛苦。应用程序內购买

In App Purchases(IAP 应用程序內购买): 完全攻略的更多相关文章

  1. WPF ClickOnce应用程序IIS部署发布攻略

    WPF程序非常适合公司内网使用,唯一缺点就是客户端要安装.net框架4.0.优势也很明显,在客户端运行的是一个WinForm程序,自动下载,可以充分利用客户机的性能,而且是以当前的Windows用户权 ...

  2. unity3d 嵌入iOS的 In App Purchase 应用程序内购买

    Unity做东西是快,但是有些功能是需要额外开发的,比如 IAP (In App Purchase,应用程序内购买) 还好unity提供了灵活的扩展功能,允许嵌入原生代码来做一些unity未实现的功能 ...

  3. 林兴爆料小程序很快可以支持各个 App 直接打开小程序

    在微信开放平台基础高级产品经理林兴演讲的当场,他爆料了微信小程序一个轰动性新能力:小程序很快可以支持各个 App 直接打开小程序!没错,你没有听错,简单来说,在不久以后,所有的 App 里面都可以看到 ...

  4. 微信即将支持App直接打开小程序

    “今年,微信将更快速地支持各APP直接打开小程序.”微信开放平台基础部高级产品经理林兴表示.对于官方即将支持的App直接打开小程序,林兴解释说,正如大家都喜欢微信钱包里的各种便捷服务,以后一个旅游攻略 ...

  5. 怎么找到苹果App Store的应用程序下载链接地址

    http://jingyan.baidu.com/article/6dad5075f6fa79a123e36e85.html 怎么找到苹果App Store的应用程序下载链接地址 每个上传到苹果app ...

  6. 【纯&&num;183&semi;技术干货】更 App 化的小程序开发

    2018 年 10 月13 日,由又拍云和知晓云联合主办的 Open Talk 丨2018 小程序开发者沙龙系列活动广州站拉开帷幕,糗事百科前端负责人宋航在沙龙上做了<更App化的小程序开发&g ...

  7. App拉起小程序提示跳转失败

    App拉起小程序提示跳转失败 req.userName = "gh_8afldfalsejw"; // 小程序的原始ID,注意不是Appid

  8. 小程序支持打开APP了 还有小程序的标题栏也可以自定义

    就在刚刚,小程序上线两个新能力——小程序支持打开APP了,小程序的标题栏区域开放自定义.用户可以在小程序里更方便地获取到APP的服务了——APP链接分享到微信,打开小程序页面后,用户从该小程序页面里, ...

  9. uni-app - 支付(app支付、小程序支付、h5(微信端)支付)

    App支付.小程序支付.h5(微信端)支付 APP支付(内置) appPay.js /** * 5+App支付,仅支持支付宝以及微信支付 * * 支付宝Sdk集成,微信sdk未集成 * * @para ...

随机推荐

  1. 第二章 深入 C&num; 数据类型

    第二章 深入 C# 数据类型 1.封装又称信息隐藏,是指利用抽象数据类型将数据和数据的操作结合在一起,使其构成一个不可分割的独立实体,尽可能的隐藏内部的细节,只保留一些对外接口,使之于外部发生联系. ...

  2. 初识redis——mac下搭建redis环境

    一.redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有 ...

  3. Swift - 28 - 内部参数名和外部参数名

    //: Playground - noun: a place where people can play import UIKit // 外部参数的作用是为了让程序员调用代码的时候能清晰的看出所传参数 ...

  4. 基于vue2&period;0的网易云音乐 &lpar;实时更新&rpar;

    本人在自学vue,之后想在学习过程中加以实践.由于之前有做过jquery的播放器效果,ui仿照网易云,地址 www.daiwei.org/music 于是就想做vue 的网易云播放器,网上也有类似的项 ...

  5. Centos 配置开机启动脚本启动 docker 容器

    Centos 配置开机启动脚本启动 docker 容器 Intro 我们的 Centos 服务器上部署了好多个 docker 容器,因故重启的时候就会导致还得手动去手动重启这些 docker 容器,为 ...

  6. MonkeyRunner 综合实践

    综合实践 测试场景 连接设备,自动安装并启动考研帮app 启动后登录账号(账号zxw1234 密码:zxw123456),然后截图并保存到指定文件位置. 思路分析 连接设备 安装app 启动app 输 ...

  7. 错误模块名称&colon; KERNELBASE&period;dll错误

    今天在部署一个C/S程序的时候出了bug,日志都没有记载:本地调试当然是没问题的,所以不是代码问题,百度之发现KERNELBASE.dll这个文章说的比较靠谱,仔细研究了自己的配置文件后,果然是配置文 ...

  8. &lbrack;转&rsqb; VS2017 打包安装程序

    前言 C#写好一个应用程序,总想分享给自己的朋友或者上架,然而被困在打包之外,这次为大家带来近期我的经验,经过几天的摸索,发现网上的教程并不全面,会给初学者带来很多疑问,这里将做些问题描述与解答. / ...

  9. Taxi

    /* After the lessons n groups of schoolchildren went outside and decided to visit Polycarpus to cele ...

  10. 优雅高效的免费在线APP原型工具

    前往:xiaopiu 打开浏览器即可享受软件级的流畅体验!云端组件库.交互动效自定义.高效友好的操作方式让您的创意即刻呈现!