Browsed by
分类:移动开发

使用多个iOS ANE的duplicate symbol问题

使用多个iOS ANE的duplicate symbol问题

当使用AIR进行iOS应用开发时,如果用到了多个iOS ANE,有时在打包时会遇到duplicate symbol问题,比如:

ld: duplicate symbol _ContextInitializer .....

这个问题的原因是由于多个ANE的iOS原生代码中有同名的类或全局变量。解决方法便是统一给它们加上一个前缀,比如公司和产品的名字组合。

如果使用ANE模板项目创建的ANE,会有 ContextInitializer等同名方法,注意修改

 

其他关于开发ANE需要注意的问题可以参见这篇文章:

原文:20 tips for creating Air Native Extensions for iOS

中文翻译:20条开发AIR Native Extension的建议

ATF加载时间测试(IOS)

ATF加载时间测试(IOS)

最近在优化项目的资源文件atf加载上传时间,在iPhone上做了一点测试,数据共享下!

atf_upload_test

 

说明:

整图—整张640×1136的图,直接转的atf(命令参考:png2atf -c p -q 0 -n 0,0  -i a.png -o a.atf

拆分成4个:即把整图分别拆分为512×1024、128×1024、512×112和128×112这个尺寸的小图。

硬件环境:iPhone4/4s/5

软件环境:FB4.7+airsdk14+Starling1.4

从上面表中可以看出在iPhone4上基本近3s的时间(我记得去年在iPhone4上测试640×960的整图也基本是这个时间,看来air+starling改进很多的样子)。目前iPhone4的用户比例大约6%(朋友提供的,数据不权威,真实情况会有浮动),WWDC2014刚刚开完,iPhone6再过一段时间也要发布了,相信iPhone4用户比例在新机发布后会更进一步降低,当然如果那个iPhone4用户依然还不愿换手机的话,那么我想你也别指望让他给你的游戏付费了。总之,目前的开发标准应该瞄准iPhone4s,确保在iPhone4s上运行流畅即可,至于iPhone4,呵呵,不崩溃就行了!

关于安卓,一直以来,安卓的atf上传时间都要比iPhone快一些,atf品质也好一些,搞的定iPhone就不用担心安卓了!

在PC,加载相应png格式资源,整图需200+毫秒,而拆分后的,反倒需要400+毫秒。

iOS 7.1下itms-services在线安装失败的解决方法

iOS 7.1下itms-services在线安装失败的解决方法

iOS 7.1正式版发布了,之前使用itms-services://URL方式在线安装ipa文件的方法却失效了,点击的时候报错为:“无法安装应用程序,因xxx.com的证书无效”(错误界面见下图),这应该怎么解决呢?

其实iOS 7.1修改了manifest.plist文件的访问协议,之前可以通过http协议访问,在iOS 7.1之后必须使用https协议方式访问。

ios7.1_https

 

 

 

比如之前的链接代码为:

itms-services://?action=download-manifest&url=http://example.com/manifest.plist

在iOS 7.1之后,就需要修改为:

itms-services://?action=download-manifest&url=https://example.com/manifest.plist

需要一个SSL证书才能够实现在线安装ipa文件的功能。

 

//——————-  延伸: 关于https设置 ———————————-

1.upload your app.plist to dropbox

2.get shared link of app.plist, like https://www.dropbox.com/s/qgknrfngaxazm38/app.plist

3.replace www.dropbox.com with dl.dropboxusercontent.com in the link, like https://dl.dropboxusercontent.com/s/qgknrfngaxazm38/app.plist

4.write your download.html like <a href=”itms-services://?action=download-manifest&url=https://dl.dropboxusercontent.com/s/qgknrfngaxazm38/app.plist”>INSTALL!!</a>

5.upload the download.html to dropbox

6.get shared link of download.html, like https://www.dropbox.com/s/gnoctp7n9g0l3hx/download.html

7.replace www.dropbox.com with dl.dropboxusercontent.com in the second link as well, like https://dl.dropboxusercontent.com/s/gnoctp7n9g0l3hx/download.html

Now, visit https://dl.dropboxusercontent.com/s/gnoctp7n9g0l3hx/download.html in your device, you can install the app like before.

 

这个是通过上传dropbox来解决,事实上,只要找个可以以https方式共享外链的网盘,把plist文件上传就可以了!

 

—————–2014.06.23

关于https文件,最近发现 七牛网盘支持ssl,可以搞定!

链接:七牛云盘

这个网盘貌似专门为开发者服务的,不想其他的一大堆广告什么的,总之有点不一样。

 

相关文章:  在未越狱iPhone上安装测试版ipa

 

 

 

在未越狱iPhone上安装测试版ipa

在未越狱iPhone上安装测试版ipa

对于未越狱的iPhone上安装测试版ipa,可通过itms-services协议来实现。

方法如下:

1.需要一个html文件,引导下载用户在线安装ipa

[codesyntax lang=”php”]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>一键安装掌上综调iPhone版</title>
  </head>

  <body>
        <a href='itms-services://?action=download-manifest&url=http://222.177.4.242/ios/d.plist(plist地址)'>安装app</a>
  </body>
</html>

[/codesyntax]

2.plist文件

[codesyntax lang=”php”]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>items</key>
   <array>
       <dict>
           <key>assets</key>
           <array>
               <dict>
                   <key>kind</key>
                   <string>software-package</string>
                   <key>url</key>
                   <string>http://127.0.0.1/latest/ipa/tue.ipa(安装包的url)</string>
               </dict>
               <dict>

                   <key>kind</key>
                   <string>display-image</string>
                   <key>needs-shine</key>
                   <true/>
                   <key>url</key>
                   <string>图片的地址</string>
               </dict>
      <dict>
                   <key>kind</key>
                   <string>full-size-image</string>
                   <key>needs-shine</key>
                   <true/>
                   <key>url</key>
                   <string>图片的地址</string>
               </dict>
           </array>
           <key>metadata</key>
           <dict>
               <key>bundle-identifier</key>
               <string>com.xinchun(和ipa中的相同)</string>
               <key>bundle-version</key>
               <string>1.0.0</string>
               <key>kind</key>
               <string>software</string>
               <key>subtitle</key>
               <string>Tue</string>
               <key>title</key>
               <string>Tue</string>
           </dict>
       </dict>
   </array>
</dict>
</plist>

[/codesyntax]

3.使用iphone自带的safari浏览器,浏览http://222.177.4.242/ios/d.html文件,即可安装了。

注意:有的iPhone上访问到网页,点击链接没有反映,这时候要查看safari浏览器的设置了,看有没有禁用弹出窗口什么的

相关文章:  iOS 7.1下itms-services在线安装失败的解决方法

第一个IOS的ANE苦逼之路

第一个IOS的ANE苦逼之路

 

概要:本文只是记录作者开发ANE的心得,并不会教你一步一步制作一个ANE,不过文中附有其他教程链接,可供参考!

 

作为一个只会as3的aser,想折腾个ANE实在太苦逼了,所幸,今天终于折腾出一个!

ane

1.先装黑苹果,各种翻论坛,安装包已经不记得下了多少个,总是卡到这里或那里,搞了n天,终于用Vbox装上了mac 10.7(幸好之前买电脑时cpu是i5,内存又加了一根现在有6G了)

2.又在ucai.cn自学了一段时间objective-c,每天晚上看视频,学着敲代码,知道了一些基本的语法。

3.学了一段时间,看看github上别人的ANE,有的可以小改一下。

4.尝试着写ane,这中间真是各种坑,还好找到一些资料,推荐几篇不错的:

第一个ane,是做了一个获取设备mac地址的,其实实现什么功能都是浮云了,只要搞通了AS3和OC的相互调用,功能就看实际需求了!

说起as+oc的对接,就不得不提一下 ANE的Xcode模版xcode-template-ane,这个可以省不少代码,不用配置,还可以直接生成ane,不过要生成ane还需要AIR SDK环境等,如果你是直接用MAC PRO开发,Flash Builder和XCode一起用,就很方便了,像我这中苦逼的用虚拟机黑苹果不敢点太快怕机器卡死的aser开发者,只用下xcode生成的.a库文件就可以了!这个模版可以帮菜鸟oc同学设置好模版,我们只需要写逻辑就行了!

在AS3和OC之间的数据交互是用的FREObejct,对于AS3来说 还是和平常用法一样,Boolean,String等随便传,但是在oc中得到的都是FREObejct类型,需要从FREObejct中提取转换成BOOL、NSString等,同样,oc方法的返回值也需要将BOOL、NSString等类型转换成FREObejct,传给as3,在as3中可以直接得到的就是Boolean、String不需要再转换,想必AIR已经自动转换好了。FREObejct和oc中的类型的转换建议还是再封装一个类比较好,这里是Maom的封装的方法ANEFun,可以参考一下,Maom的ANEList也蛮全面,很给力!

另外一个坑就是打包ANE,前面说过用xcode-template-ane模版的话,在创建.ane目标的时候,会自动调用generateANE.sh脚本,从而自动生成ANE。在window上呢?只有命令行了,当然那个《ANE打包工具2013版》打包工具在不会打包的时候也可以用一下,推荐还是命令行,自己写个批处理工具最好!

命令如下:

bin/adt -package -storetype pkcs12 -keystore .p12文件名称.p12 -storepass .p12文件的密码 -target ane 需要生成的ane的名称.ane extension.xml -swc swc名称.swc -platform 平台名称 library.swf 本机扩展库

(我习惯把 bin/adt 直接改为FB安装包路径名)

打包的细节可以参考上文提到的 : 如何打包ANE(前后几篇相关都看,有坑的,错误提示也很少,要靠自己想);

这里还有最新发现的 打包ANE的视频教程 !

 

小记:2014.03.06

项目引用多个ane的话,ios的ane中的类名不能相同,不然编译会冲突,不妨把多个功能些到一个ane里,或者在些单独的ane时候尽量类名长一点

iOS应用内付费(IAP)开发步骤列表【转】

iOS应用内付费(IAP)开发步骤列表【转】

前两天和服务端同事一起,完成了应用内付费(以下简称IAP, In app purchase)的开发工作。步骤繁多,在此把开发步骤列表整理如下。因为只是步骤列表,所以并不含详细的说明教程,需要看教程的新手,可以看我附在最后的一些参考链接。

配置Developer.apple.com

登录到Developer.apple.com,然后进行以下步骤:

  1. 为应用建立建立一个不带通配符的App ID
  2. 用该App ID生成和安装相应的Provisioning Profile文件。

配置iTunes Connect

登录到iTunes Connet,然后进行以下步骤:

  1. 用该App ID创建一个新的应用。
  2. 在该应用中,创建应用内付费项目,选择付费类型,通常可选的是可重复消费(Consumable)的或是永久有效(Non-Consumable)的2种,然后设置好价格和Product ID以及购买介绍和截图即可,这里的Product ID是需要记住的,后面开发的时候需要。如下图所示: 
  3. 添加一个用于在sandbox付费的测试用户,如下图所示。注意苹果对该测试用户的密码要求 和正式账号一样,必须是至少8位,并且同时包含数字和大小写字母: 
  4. 填写相关的税务,银行,联系人信息。如下图所示: 

开发工作(ios端)

1、 在工程中引入 storekit.framework 和 #import <StoreKit/StoreKit.h>

2、 获得所有的付费Product ID列表。这个可以用常量存储在本地,也可以由自己的服务器返回。

3、 制作一个界面,展示所有的应用内付费项目。这些应用内付费项目的价格和介绍信息可以是自己的服务器返回。但如果是不带服务器的单机游戏应用或工具类应用,则可以通过向App Store查询获得。我在测试时发现,向App Store查询速度非常慢,通常需要2-3秒钟,所以不建议这么做,最好还是搞个自己的服务器吧。

4、当用户点击了一个IAP项目,我们先查询用户是否允许应用内付费,如果不允许则不用进行以下步骤了。代码如下:

1
2
3
4
5
6
if ([SKPaymentQueue canMakePayments]) {
    // 执行下面提到的第5步:
    [self getProductInfo];
} else {
    NSLog(@"失败,用户禁止应用内付费购买.");
}

5、 我们先通过该IAP的ProductID向AppStore查询,获得SKPayment实例,然后通过SKPaymentQueue的 addPayment方法发起一个购买的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 下面的ProductId应该是事先在itunesConnect中添加好的,已存在的付费项目。否则查询会失败。
- (void)getProductInfo {
  NSSet * set = [NSSet setWithArray:@[@"ProductId"]];
  SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
  request.delegate = self;
  [request start];
}

// 以上查询的回调函数
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    NSArray *myProduct = response.products;
    if (myProduct.count == 0) {
        NSLog(@"无法获取产品信息,购买失败。");
        return;
    }
    SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

6、 在viewDidLoad方法中,将购买页面设置成购买的Observer。

1
2
3
4
5
6
7
8
9
10
- (void)viewDidLoad {
    [super viewDidLoad];
    // 监听购买结果
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

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

7、 当用户购买的操作有结果时,就会触发下面的回调函数,相应进行处理即可。

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
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased://交易完成
                NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier);
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed://交易失败
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored://已经购买过该商品
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchasing:      //商品添加进列表
                NSLog(@"商品添加进列表");
                break;
            default:
                break;
        }
    }

}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    // Your application should implement these two methods.
    NSString * productIdentifier = transaction.payment.productIdentifier;
    NSString * receipt = [transaction.transactionReceipt base64EncodedString];
    if ([productIdentifier length] > 0) {
        // 向自己的服务器验证购买凭证
    }

    // Remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    if(transaction.error.code != SKErrorPaymentCancelled) {
        NSLog(@"购买失败");
    } else {
        NSLog(@"用户取消交易");
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
  // 对于已购商品,处理恢复购买的逻辑
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

8、服务器验证凭证(Optional)。如果购买成功,我们需要将凭证发送到服务器上进行验证。考虑到网络异常情况,iOS端的发送凭证操作应该进行持久化,如果程序退出,崩溃或网络异常,可以恢复重试。

开发工作(服务端)

服务端的工作比较简单,分4步:

  1. 接收ios端发过来的购买凭证。
  2. 判断凭证是否已经存在或验证过,然后存储该凭证。
  3. 将该凭证发送到苹果的服务器验证,并将验证结果返回给客户端。
  4. 如果需要,修改用户相应的会员权限。

考虑到网络异常情况,服务器的验证应该是一个可恢复的队列,如果网络失败了,应该进行重试。

与苹果的验证接口文档在这里。简单来说就是将该购买凭证用Base64编码,然后POST给苹果的验证服务器,苹果将验证结果以JSON形式返回。

苹果AppStore线上的购买凭证验证地址是https://buy.itunes.apple.com/verifyReceipt ,测试的验证地址是:https://sandbox.itunes.apple.com/verifyReceipt

原文:http://blog.devtang.com/blog/2012/12/09/in-app-purchase-check-list/