helu 0.5 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +57 -8
- data/lib/helu.rb +1 -0
- data/lib/project/fake_helu.rb +35 -0
- data/lib/project/helu.rb +10 -8
- data/lib/project/product_info_fetcher.rb +115 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53fb21dab5afe5f99d560e4326b61e8222040089
|
4
|
+
data.tar.gz: 743acc254c9f25923817058f0028d1ddbf35fc2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45cae952adc479e019b24bce56d7c64e7a5ab68aa5d4545b3736e0220099b8848ca167e16e3df84d72f67f0c53ed8a1880d010497dd5778630511e374e4bf7cf
|
7
|
+
data.tar.gz: 41dff4c9c13efa64328622dfa0543996fb0eefbd8c5ec0078bed9c5cfbb655b61685986efab632adbb4b2b5bacc5ad46a8b10e64d74c7b12b39aba142f7437b5
|
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# Helu
|
2
2
|
|
3
3
|
[](https://travis-ci.org/ivanacostarubio/helu)
|
4
4
|
|
5
|
+
In-App purchases for RubyMotion.
|
6
|
+
|
7
|
+

|
5
8
|
|
6
9
|
## Installation
|
7
10
|
|
@@ -16,6 +19,7 @@ And then execute:
|
|
16
19
|
Or install it yourself as:
|
17
20
|
|
18
21
|
$ gem install helu
|
22
|
+
|
19
23
|
|
20
24
|
## USAGE
|
21
25
|
|
@@ -47,17 +51,62 @@ The transaction object on the lambda is the one we get from Apple; Therefore, it
|
|
47
51
|
@helu.restore
|
48
52
|
|
49
53
|
|
50
|
-
|
54
|
+
#### Make sure that if your code ever throws out the Helu object, it better also close the store before doing so.
|
51
55
|
|
52
56
|
@helu.close
|
53
57
|
|
58
|
+
### Supported types of In App Purchases
|
59
|
+
|
60
|
+
+ Consumables and Non-Consumables are supported.
|
61
|
+
+ Auto-Renewable subscriptions and Non-Renewing Subscriptions are not supported yet. However, we would love some help making it happen.
|
62
|
+
|
63
|
+
### Requesting product information:
|
64
|
+
|
65
|
+
Asynchronous, raw:
|
66
|
+
|
67
|
+
inapps = %w[first second third]
|
68
|
+
@x = Helu::ProductInfoFetcher.new(inapps) do |pi|
|
69
|
+
p pi
|
70
|
+
end
|
71
|
+
|
72
|
+
Asynchronous, wrapped in method call:
|
73
|
+
|
74
|
+
Helu::ProductInfoFetcher.fetch(inapps) do |pi|
|
75
|
+
p pi
|
76
|
+
end
|
77
|
+
|
78
|
+
Synchronous:
|
79
|
+
|
80
|
+
pi = Helu::ProductInfoFetcher.fetch(inapps)
|
81
|
+
p pi
|
82
|
+
|
83
|
+
|
84
|
+
All three calls return hash of the following form:
|
85
|
+
|
86
|
+
{
|
87
|
+
"inapp_id": {
|
88
|
+
id: "inapp_id",
|
89
|
+
title: "inapp_localized_title",
|
90
|
+
description: "inapp_localized_description",
|
91
|
+
price: "0.89", # float
|
92
|
+
currency: "EUR",
|
93
|
+
price_str: "\u20AC0.89",
|
94
|
+
}, # ....
|
95
|
+
}
|
96
|
+
|
54
97
|
|
55
98
|
## Example App:
|
56
99
|
|
57
|
-
[You can find an example app here](https://github.com/ivanacostarubio/helu-example).
|
58
|
-
|
59
|
-
|
60
|
-
## Supported types of In App Purchases
|
100
|
+
[You can find an example app here](https://github.com/ivanacostarubio/helu-example).
|
101
|
+
Remember that for this to work properly, you must add your app identifier to the Rakefile.
|
102
|
+
|
61
103
|
|
62
|
-
|
63
|
-
|
104
|
+
## License
|
105
|
+
|
106
|
+
Helu is relase under the [MIT license](http://opensource.org/licenses/MIT).
|
107
|
+
|
108
|
+
## Credits
|
109
|
+
|
110
|
+
Ivan Acosta-Rubio | Initial work
|
111
|
+
Michal J. | Product Info Fetcher
|
112
|
+
Simon Traels Ravn | Removing Observer and Bug fixes.
|
data/lib/helu.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
class FakeHelu
|
2
|
+
attr_reader :product_id
|
3
|
+
attr_accessor :storage, :winning, :restore, :fail
|
4
|
+
|
5
|
+
def initialize(product_id)
|
6
|
+
@produc_id = product_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def bought?
|
10
|
+
#TODO. Be able to switch this
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
# just implementing Helu's interface
|
16
|
+
end
|
17
|
+
|
18
|
+
def buy
|
19
|
+
winning.call(fake_transaction)
|
20
|
+
end
|
21
|
+
|
22
|
+
def fake_fail
|
23
|
+
# TODO: We need to implement a way to fake a fail
|
24
|
+
end
|
25
|
+
|
26
|
+
def restore
|
27
|
+
winning.call(fake_transaction)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def fake_transaction
|
33
|
+
""
|
34
|
+
end
|
35
|
+
end
|
data/lib/project/helu.rb
CHANGED
@@ -3,6 +3,13 @@ class Helu
|
|
3
3
|
attr_reader :product_id
|
4
4
|
attr_accessor :storage, :winning, :restore, :fail
|
5
5
|
|
6
|
+
class <<self
|
7
|
+
# see product_info_fetcher.rb for info
|
8
|
+
def fetch_product_info(*products, &b)
|
9
|
+
ProductInfoFetcher.fetch(*products, &b)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
6
13
|
def initialize(product_id)
|
7
14
|
@product_id = product_id
|
8
15
|
SKPaymentQueue.defaultQueue.addTransactionObserver(self)
|
@@ -26,11 +33,8 @@ class Helu
|
|
26
33
|
@storage.all.include?(product_id)
|
27
34
|
end
|
28
35
|
|
29
|
-
# private
|
30
|
-
|
31
36
|
def finishTransaction(transaction, wasSuccessful:wasSuccessful)
|
32
37
|
SKPaymentQueue.defaultQueue.finishTransaction(transaction)
|
33
|
-
produt_id = transaction.payment.productIdentifier
|
34
38
|
if wasSuccessful
|
35
39
|
@winning.call(transaction)
|
36
40
|
storage.add(product_id)
|
@@ -48,11 +52,9 @@ class Helu
|
|
48
52
|
end
|
49
53
|
|
50
54
|
def failedTransaction(transaction)
|
51
|
-
|
52
|
-
|
53
|
-
if (transaction.error.code != SKErrorPaymentCancelled)
|
55
|
+
if transaction.error && (transaction.error.code != SKErrorPaymentCancelled)
|
54
56
|
finishTransaction(transaction, wasSuccessful:false)
|
55
|
-
elsif transaction.error.code == SKErrorPaymentCancelled
|
57
|
+
elsif transaction.error && (transaction.error.code == SKErrorPaymentCancelled)
|
56
58
|
@fail.call(transaction)
|
57
59
|
else
|
58
60
|
SKPaymentQueue.defaultQueue.finishTransaction(transaction)
|
@@ -119,4 +121,4 @@ class Helu
|
|
119
121
|
|
120
122
|
end
|
121
123
|
|
122
|
-
end
|
124
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
=begin
|
2
|
+
# Sample use:
|
3
|
+
## Asynchronous, raw:
|
4
|
+
inapps = %w[first second third]
|
5
|
+
@x = Helu::ProductInfoFetcher.new(inapps) do |pi|
|
6
|
+
p pi
|
7
|
+
end
|
8
|
+
|
9
|
+
## Asynchronous, wrapped in method call:
|
10
|
+
Helu::ProductInfoFetcher.fetch(inapps) do |pi|
|
11
|
+
p pi
|
12
|
+
end
|
13
|
+
|
14
|
+
## Synchronous:
|
15
|
+
pi = Helu::ProductInfoFetcher.fetch(inapps)
|
16
|
+
p pi
|
17
|
+
|
18
|
+
|
19
|
+
# All three calls return hash of the following form:
|
20
|
+
# {
|
21
|
+
# "inapp_id": {
|
22
|
+
# id: "inapp_id",
|
23
|
+
# title: "inapp_localized_title",
|
24
|
+
# description: "inapp_localized_description",
|
25
|
+
# price: "0.89", # float
|
26
|
+
# currency: "EUR",
|
27
|
+
# price_str: "\u20AC0.89",
|
28
|
+
# },
|
29
|
+
# # ...
|
30
|
+
# }
|
31
|
+
=end
|
32
|
+
class Helu
|
33
|
+
class ProductInfoFetcher
|
34
|
+
@@mutex = Mutex.new
|
35
|
+
@@cache = {}
|
36
|
+
def initialize(*products, &b)
|
37
|
+
raise LocalJumpError, "block expected" if b.nil?
|
38
|
+
@callback = b
|
39
|
+
@products = products.flatten
|
40
|
+
|
41
|
+
# all cached? skip the call...
|
42
|
+
if (@@cache.keys & @products).sort == @products.sort
|
43
|
+
h = @products.inject({}) { |m, prod| m[prod] = @@cache[prod]; m }
|
44
|
+
@callback.call(h)
|
45
|
+
else
|
46
|
+
@sr = SKProductsRequest.alloc.initWithProductIdentifiers(@products)
|
47
|
+
@sr.delegate = self
|
48
|
+
@sr.start
|
49
|
+
end
|
50
|
+
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def productsRequest(req, didReceiveResponse: resp)
|
55
|
+
if resp.nil?
|
56
|
+
@callback.call(nil)
|
57
|
+
else
|
58
|
+
h = resp.products.inject({}) { |m, prod|
|
59
|
+
m.merge(sk_to_hash(prod))
|
60
|
+
}
|
61
|
+
@@mutex.synchronize { @@cache.merge!(h) }
|
62
|
+
@callback.call(h)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def sk_to_hash(sk)
|
69
|
+
nf = NSNumberFormatter.alloc.init
|
70
|
+
nf.setFormatterBehavior(NSNumberFormatterBehavior10_4)
|
71
|
+
nf.setNumberStyle(NSNumberFormatterCurrencyStyle)
|
72
|
+
nf.setLocale(sk.priceLocale)
|
73
|
+
price_str = nf.stringFromNumber(sk.price)
|
74
|
+
|
75
|
+
{
|
76
|
+
sk.productIdentifier => {
|
77
|
+
id: sk.productIdentifier,
|
78
|
+
title: sk.localizedTitle,
|
79
|
+
description: sk.localizedDescription,
|
80
|
+
price: sk.price,
|
81
|
+
currency: sk.priceLocale.objectForKey(NSLocaleCurrencyCode),
|
82
|
+
price_str: price_str,
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
class <<self
|
88
|
+
# make a sync call out of an async one
|
89
|
+
def call_synchronized(method, *args)
|
90
|
+
finished = false
|
91
|
+
result = nil
|
92
|
+
send(method, *args) do |res|
|
93
|
+
result = res
|
94
|
+
finished = true
|
95
|
+
end
|
96
|
+
sleep 0.1 until finished
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
def fetch(*products, &b)
|
101
|
+
products.flatten!
|
102
|
+
if b.nil?
|
103
|
+
call_synchronized(:fetch, *products)
|
104
|
+
else
|
105
|
+
new(*products, &b)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def clear_cache
|
110
|
+
@@mutex.synchronize { @@cache = {} }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: helu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Acosta-Rubio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
description: 'RubyMotion :: StoreKit Wrapper :: Allows In App Purchases '
|
@@ -33,7 +33,9 @@ extra_rdoc_files: []
|
|
33
33
|
files:
|
34
34
|
- README.md
|
35
35
|
- lib/helu.rb
|
36
|
+
- lib/project/fake_helu.rb
|
36
37
|
- lib/project/helu.rb
|
38
|
+
- lib/project/product_info_fetcher.rb
|
37
39
|
homepage: http://www.ivanacostarubio.com
|
38
40
|
licenses:
|
39
41
|
- MIT
|
@@ -44,17 +46,17 @@ require_paths:
|
|
44
46
|
- lib
|
45
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
46
48
|
requirements:
|
47
|
-
- -
|
49
|
+
- - ">="
|
48
50
|
- !ruby/object:Gem::Version
|
49
51
|
version: '0'
|
50
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
53
|
requirements:
|
52
|
-
- -
|
54
|
+
- - ">="
|
53
55
|
- !ruby/object:Gem::Version
|
54
56
|
version: '0'
|
55
57
|
requirements: []
|
56
58
|
rubyforge_project:
|
57
|
-
rubygems_version: 2.
|
59
|
+
rubygems_version: 2.2.2
|
58
60
|
signing_key:
|
59
61
|
specification_version: 4
|
60
62
|
summary: RubyMotion StoreKit Wrapper
|