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

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

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

  1. 在 iPhone Developer Portal中, 选择左边的Provisioning部分
  2. 确保你处于Development 标签下, 按下右上角的 “New Profile”
  3. 填入所需信息并指向你刚创建的唯一的App ID
  4. 如果你在Actions条目下看到 “Pending”,那么请按下“Development”标签标题进行刷新
  5. 点击 “Download” 下载新的profile文件
  6. 将profile文件拖入到Dock中Xcode图标上进行安装
  7. 如果你想在硬盘上保存provisioning profile,那么你可以按如下步骤手工安装profile:
    1. 在Xcode中, 选择 Window > Organizer
    2. 选择左边 “Provisioning Profiles” 分类
    3. Ctrl-按下profile > Reveal in Finder
    4. 将新profile拖入到 profile Finder 窗口

3. 更新Xcode 设置

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

  1. 编辑项目 .plist 文件使其 Bundle ID 与 App ID 匹配。忽略ID开始部分的字母数字序列。例如,在Developer Portal中你的App ID为“7DW89RZKLY.com.runmonster.runmonsterfree”,那么在Bundle ID中你只需输入“com.runmonster.runmonsterfree” 。
  2. 编辑项目的 target 信息以使用新的provisioning profile:
    1. 选取 Project > Edit Active Target
    2. 选取顶部“Build” 标签
    3. 选取需要的 configuration (通常为 Debug)
    4. 在Code Signing Identity中选择新的provisioning profile
    5. 在Code Signing Identity之下的行中(可能名为 Any iPhone OS Device)选择新的provisioning profile

4. 添加你的应用程序

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

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

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

  1. 登录到 http://developer.apple.com/iphone
  2. 点击右边链接进入 iTunes Connect
    • 注意:你必须先登录到developer.apple.com,否则会有不测发生(译者注:具体是什么不测我也不太清楚,胆大的请自己试一下)
  3. 在 iTunes Connect主页点击 “Manage Your Applications”
  4. 在右上角点击“Create New Application”
  5. 填写程序所需的一切信息。当要求程序二进制码时,请选择稍后上传选项。

5. 提交程序二进制码

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

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

  1. 生成App Store发布版程序

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

      • 获取iPhone发行许可证
      • 创建并下载在App Store发行所需的iPhone Distribution Provisioning Profile
      • 在Xcode中生成程序的发行版
  2. 在iTunes Connect中进入程序页
  3. 选择 “Upload Binary”
  4. 上传.zip压缩程序
  5. 如果你的程序还没有100%完成以进行审核,那么请点击iTunes Connect中你程序首页中的 “Reject Binary”链接。程序的状态应该更新为 “Developer Rejected”.

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

6. 添加产品

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

  1. 确保登录到 http://developer.apple.com/iphone
  2. 进入 iTunes Connect 主页
  3. 点击 “Manage Your in App Purchases” 链接
  4. 点击 “Create New”
  5. 选择你的程序
  6. 填写下列产品信息:
    • 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%完成的程序二进制码时,产品也会随之提交。
  7. 点击 “Save”

7. 编写代码

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

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

  1. 1.添加 StoreKit framework 到你的项目中。
  2. 2.添加SKProduct引用到你的 .h 文件中:
1
2
3
4
5
6
7
8
9
10
11
// InAppPurchaseManager.h

#import <StoreKit/StoreKit.h>

#define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification"

@interface InAppPurchaseManager  :  NSObject <SKProductsRequestDelegate>
{
    SKProduct  *proUpgradeProduct;
    SKProductsRequest  *productsRequest;
}

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

  1. 3.产品请求,并在相应.m文件中实现代理协议:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// InAppPurchaseManager.m

-  ( void )requestProUpgradeProductData
{
     NSSet  *productIdentifiers  =  [ NSSet setWithObject : @ "com.runmonster.runmonsterfree.upgradetopro"  ];
    productsRequest  =  [ [SKProductsRequest alloc ] initWithProductIdentifiers :productIdentifiers ];
    productsRequest.delegate  = self;
     [productsRequest start ];
   
     // we will release the request object in the delegate callback
}

#pragma mark -
#pragma mark SKProductsRequestDelegate methods

-  ( void )productsRequest : (SKProductsRequest  * )request didReceiveResponse : (SKProductsResponse  * )response
{
     NSArray  *products  = response.products;
    proUpgradeProduct  =  [products count ]  == 1 ?  [ [products firstObject ] retain ]  :  nil;
     if  (proUpgradeProduct )
     {
        NSLog ( @ "Product title: %@" , proUpgradeProduct.localizedTitle );
        NSLog ( @ "Product description: %@" , proUpgradeProduct.localizedDescription );
        NSLog ( @ "Product price: %@" , proUpgradeProduct.price );
        NSLog ( @ "Product id: %@" , proUpgradeProduct.productIdentifier );
     }
   
     for  ( NSString  *invalidProductId  in response.invalidProductIdentifiers )
     {
        NSLog ( @ "Invalid product id: %@" , invalidProductId );
     }
   
     // finally release the reqest we alloc/init’ed in requestProUpgradeProductData
     [productsRequest release ];
   
     [ [ NSNotificationCenter defaultCenter ] postNotificationName :kInAppPurchaseManagerProductsFetchedNotification object :self userInfo : nil ];
}

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

  • 指定产品id时,你必须使用完整产品id。例如,上例中使用 “com.runmonster.runmonsterfree.upgradetopro”。仅使用 “upgradetopro” 将不会正常工作。
  • 如果在productsRequest:didReceiveResponse:中response.products 为 nil,而你的产品id出现于 response.invalidProductIdentifers 数组中时,那么请做好心理准备开始一场徒劳的搜索战吧。 StoreKit API没有提供任何帮助,也没有任何指示关于为什么你的id是无效的。很可爱,不是吗?
  • SKProduct类提供了有关程序标题和描述的本地化版本,但是价格则没有本地化版本。下面是针对此疏忽提供的代码:
1
2
3
4
5
6
7
8
9
10
// SKProduct+LocalizedPrice.h

#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>

@interface SKProduct  (LocalizedPrice )

@property  (nonatomic, readonly )  NSString  *localizedPrice;

@end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SKProduct+LocalizedPrice.m

#import "SKProduct+LocalizedPrice.h"

@implementation SKProduct  (LocalizedPrice )

-  ( NSString  * )localizedPrice
{
     NSNumberFormatter  *numberFormatter  =  [ [ NSNumberFormatter alloc ] init ];
     [numberFormatter setFormatterBehavior :NSNumberFormatterBehavior10_4 ];
     [numberFormatter setNumberStyle :NSNumberFormatterCurrencyStyle ];
     [numberFormatter setLocale :self.priceLocale ];
     NSString  *formattedString  =  [numberFormatter stringFromNumber :self.price ];
     [numberFormatter release ];
     return formattedString;
}

@end

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

8. 等待几小时

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

那么,你应该等待。

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

购买产品

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

  1. 编写代码支持事务(transaction)
  2. 在iTunes Connect中添加程序测试用户
  3. 在设备中登录你的 iTunes Store 帐号
  4. 购买测试

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

1. 编写代码支持事务

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

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

首先,需要遵循 SKPaymentTransactionObserver 协议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// InAppPurchaseManager.h

// add a couple notifications sent out when the transaction completes
#define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification"
#define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification"

@interface InAppPurchaseManager  :  NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
{
    …
}

// public methods
-  ( void )loadStore;
-  ( BOOL )canMakePurchases;
-  ( void )purchaseProUpgrade;

@end

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// InAppPurchaseManager.m

#define kInAppPurchaseProUpgradeProductId @"com.runmonster.runmonsterfree.upgradetopro"

#pragma -
#pragma Public methods

//
// call this method once on startup
//
-  ( void )loadStore
{
     // restarts any purchases if they were interrupted last time the app was open
     [ [SKPaymentQueue defaultQueue ] addTransactionObserver :self ];
   
     // get the product description (defined in early sections)
     [self requestProUpgradeProductData ];
}

//
// call this before making a purchase
//
-  ( BOOL )canMakePurchases
{
     return  [SKPaymentQueue canMakePayments ];
}

//
// kick off the upgrade transaction
//
-  ( void )purchaseProUpgrade
{
    SKPayment  *payment  =  [SKPayment paymentWithProductIdentifier :kInAppPurchaseProUpgradeProductId ];
     [ [SKPaymentQueue defaultQueue ] addPayment :payment ];
}

#pragma -
#pragma Purchase helpers

//
// saves a record of the transaction by storing the receipt to disk
//
-  ( void )recordTransaction : (SKPaymentTransaction  * )transaction
{
     if  ( [transaction.payment.productIdentifier isEqualToString :kInAppPurchaseProUpgradeProductId ] )
     {
         // save the transaction receipt to disk
         [ [ NSUserDefaults standardUserDefaults ] setValue :transaction.transactionReceipt forKey : @ "proUpgradeTransactionReceipt"  ];
         [ [ NSUserDefaults standardUserDefaults ] synchronize ];
     }
}

//
// enable pro features
//
-  ( void )provideContent : ( NSString  * )productId
{
     if  ( [productId isEqualToString :kInAppPurchaseProUpgradeProductId ] )
     {
         // enable the pro features
         [ [ NSUserDefaults standardUserDefaults ] setBool : YES forKey : @ "isProUpgradePurchased"  ];
         [ [ NSUserDefaults standardUserDefaults ] synchronize ];
     }
}

//
// removes the transaction from the queue and posts a notification with the transaction result
//
-  ( void )finishTransaction : (SKPaymentTransaction  * )transaction wasSuccessful : ( BOOL )wasSuccessful
{
     // remove the transaction from the payment queue.
     [ [SKPaymentQueue defaultQueue ] finishTransaction :transaction ];
   
     NSDictionary  *userInfo  =  [ NSDictionary dictionaryWithObjectsAndKeys :transaction,  @ "transaction" ,  nil ];
     if  (wasSuccessful )
     {
         // send out a notification that we’ve finished the transaction
         [ [ NSNotificationCenter defaultCenter ] postNotificationName :kInAppPurchaseManagerTransactionSucceededNotification object :self userInfo :userInfo ];
     }
     else
     {
         // send out a notification for the failed transaction
         [ [ NSNotificationCenter defaultCenter ] postNotificationName :kInAppPurchaseManagerTransactionFailedNotification object :self userInfo :userInfo ];
     }
}

//
// called when the transaction was successful
//
-  ( void )completeTransaction : (SKPaymentTransaction  * )transaction
{
     [self recordTransaction :transaction ];
     [self provideContent :transaction.payment.productIdentifier ];
     [self finishTransaction :transaction wasSuccessful : YES ];
}

//
// called when a transaction has been restored and and successfully completed
//
-  ( void )restoreTransaction : (SKPaymentTransaction  * )transaction
{
     [self recordTransaction :transaction.originalTransaction ];
     [self provideContent :transaction.originalTransaction.payment.productIdentifier ];
     [self finishTransaction :transaction wasSuccessful : YES ];
}

//
// called when a transaction has failed
//
-  ( void )failedTransaction : (SKPaymentTransaction  * )transaction
{
     if  (transaction.error.code  != SKErrorPaymentCancelled )
     {
         // error!
         [self finishTransaction :transaction wasSuccessful : NO ];
     }
     else
     {
         // this is fine, the user just cancelled, so don’t notify
         [ [SKPaymentQueue defaultQueue ] finishTransaction :transaction ];
     }
}

#pragma mark -
#pragma mark SKPaymentTransactionObserver methods

//
// called when the transaction status is updated
//
-  ( void )paymentQueue : (SKPaymentQueue  * )queue updatedTransactions : ( NSArray  * )transactions
{
     for  (SKPaymentTransaction  *transaction  in transactions )
     {
         switch  (transaction.transactionState )
         {
             case SKPaymentTransactionStatePurchased :
                 [self completeTransaction :transaction ];
                 break;
             case SKPaymentTransactionStateFailed :
                 [self failedTransaction :transaction ];
                 break;
             case SKPaymentTransactionStateRestored :
                 [self restoreTransaction :transaction ];
                 break;
             default :
                 break;
         }
     }
}

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

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

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

2. 添加测试用户

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

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

  1. 登录到 http://developer.apple.com/iphone
  2. 进入 iTunes Connect
  3. 选择iTunes Connect首页中的 “Manage Users”
  4. 选择 “In App Purchase Test User”
  5. 选择 “Add New User”
  6. 填入用户信息. 所有信息都不必是合法的。建议使用虚假简短的email地址及简短的密码。
  7. 选择 “Save”

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

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

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

  1. 打开Settings App
  2. 点击 “Store” 行
  3. 点击 “Sign Out”

4. 购买测试

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

  1. 运行你设备中的程序
  2. 进行购买
  3. 当程序提示输入用户名和密码时,输入参数用户的信息

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

总结

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

iphone 程购买实现相关推荐

  1. 准备入手iPhone 4港版的必看!港行无锁版iPhone 4购买全攻略

    2010年7月,在港行无锁版iPhone 4即将推出倒计时之际,本人再次行动,将不惜继续折腾,以实事求是不怕困难的无畏精神再次将购买全程以文字形式记录下来,希望本流水记录同时也给众多期待和热爱港行的朋 ...

  2. iPhone 12 vs iPhone 13:哪款iPhone值得购买

    每年,iPhone新品发布时,都会有各种评测出现,例如iPhone [自动在此处插入版本号] 是被认为适合大多数人的型号,受欢迎的尺寸,并具有令人满意的功能设置,以及满足大多数预算的价格,今年的iPh ...

  3. 酷安电脑版_2020年末 平板电脑购买推荐

    这篇文章,基本包括市面上值得选购的平板,可以说涵盖了绝大部分 阅读建议:耐心看完,选择顺序,确定尺寸,确定预算,确定品牌 最近在一个类似提问 回答了平板推荐的问题 没想到一下就有很多人关注 于是决定详 ...

  4. 收银员英文缩写_如何在没有收银员的苹果商店购买东西

    收银员英文缩写 If you visit an Apple Store in the hopes of buying a new iPhone, iPad, or MacBook, you have ...

  5. 携程去哪儿移动端产品分析报告

    市场现状 1. 市场概况 随着中国居民收入逐步提高和对旅游休闲的重视程度大幅增加,居民对旅游出行的需求迅速增长.根据2015年全国旅游工作会议报告, 2014年旅游业实现平稳增长.预计国内旅游36亿人 ...

  6. 太香了!4999元就能入手iPhone 11 最高降价达900元

    今天,iPhone 11系列手机正式发售,无论是线下还是线上,都好不热闹,尤其是新配色更是备受欢迎.值得注意的是,为了吸引消费者,拼多多以500-900元的降幅开售iPhone 11系列,创下了全网最 ...

  7. 360 回应安全云盘出现交易异常;苹果官网陆续限购 iPhone;GitHub 屏蔽微软工程师的开源项目 | 极客头条...

    整理 | 屠敏 头图 | CSDN 下载自东方 IC 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦 ...

  8. 苹果电池显示维修_苹果新款 iPhone SE 屏幕维修、电池更换多少钱?

    苹果新款 iPhone SE 已经开始预购,售价为 3299 元起,将在 4 月 24 日正式发售.其最大的亮点是配备 A13 仿生芯片,支持 Touch ID,这个价格让不少果粉直呼"真香 ...

  9. 携程、飞猪?大数据杀熟的背后,到底杀死了谁?

    Linux编程点击右侧关注,免费入门到精通! again,大数据杀熟,到底杀死了谁? 近日,有微博网友"陈利人"爆料,携程疑似再次出现"大数据杀熟"现象,面临着 ...

最新文章

  1. Hive作业优化总结
  2. 【Android 逆向】使用 Python 编写 APK 批处理分析工具
  3. 2021考研数学一李林4套卷整理
  4. Java 套接字Socket
  5. python实现不重复排列组合_python之itertools的排列组合相关
  6. springboot+mybatis+mysql(增删改查xml入门编程)
  7. WEB-INF/views/menu/list.jsp (line: 26, column: 58) equal symbol expected
  8. 图书馆管理系统说明书
  9. Sublime+ZenCoding的使用
  10. android自定义控件.pdf,android自定义控件实例(linearlayout组合textview和imageview).pdf
  11. python求小于n的最大素数_找出小于n的最大素数,其中n =〜10 ^ 230 - python
  12. 物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联网与互联网物联
  13. U盘winpe启动盘的制作
  14. 软考网工-第四章知识产权与标准化
  15. 怎么快速学会Excel?每周学习5个实用小技巧
  16. Java小学算术10以内的加减乘除运算
  17. 【转贴】如何读好Phd博士
  18. 服务器集群可视化监控-Prometheus+Grafana
  19. 2022年PMP考试题型都有什么?
  20. Linux系统中CPU占用率过高问题原因分析

热门文章

  1. 基于DES加密的TCP聊天程序
  2. VMware 8安装苹果操作系统Mac OS X 10.7 Lion正式版
  3. YoutubeDNN召回的一些问题
  4. .Net6.0系列-6 .Net 6LinQ(二)常用扩展方法
  5. 关于UE5角色动画蓝图的基本操作(基础向)
  6. jzoj 3456 恭介的法则
  7. 中空介孔载银二氧化硅聚苯乙烯微球/核壳聚苯乙烯/介孔二氧化硅微球/环氧树脂复合材料的制备
  8. 听歌识曲算法技术[语音识别]
  9. uni-app的使用分享(一)
  10. mysql中长整型是longint_整型int和长整型long