Compare commits
3 commits
dev
...
feat/inapp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
15607f0beb | ||
![]() |
95aad7ac82 | ||
![]() |
63cd18dd9e |
5 changed files with 224 additions and 0 deletions
|
@ -34,6 +34,7 @@ set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/StoreKitController.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h
|
||||||
)
|
)
|
||||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE)
|
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE)
|
||||||
|
@ -46,6 +47,7 @@ set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/StoreKitController.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
24
client/platforms/ios/StoreKitController.h
Normal file
24
client/platforms/ios/StoreKitController.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef STOREKITCONTROLLER_H
|
||||||
|
#define STOREKITCONTROLLER_H
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface StoreKitController : NSObject
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
- (void)purchaseProduct:(NSString *)productIdentifier
|
||||||
|
completion:(void (^)(BOOL success,
|
||||||
|
NSString *_Nullable transactionId,
|
||||||
|
NSString *_Nullable productId,
|
||||||
|
NSError *_Nullable error))completion;
|
||||||
|
|
||||||
|
- (void)restorePurchasesWithCompletion:(void (^)(BOOL success, NSError *_Nullable error))completion;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // STOREKITCONTROLLER_H
|
141
client/platforms/ios/StoreKitController.mm
Normal file
141
client/platforms/ios/StoreKitController.mm
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#import "StoreKitController.h"
|
||||||
|
#import <StoreKit/StoreKit.h>
|
||||||
|
|
||||||
|
@interface StoreKitController () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
|
||||||
|
@property (nonatomic, copy) void (^purchaseCompletion)(BOOL success,
|
||||||
|
NSString *_Nullable transactionId,
|
||||||
|
NSString *_Nullable productId,
|
||||||
|
NSError *_Nullable error);
|
||||||
|
@property (nonatomic, copy) void (^restoreCompletion)(BOOL success, NSError *_Nullable error);
|
||||||
|
@property (nonatomic, strong) SKProductsRequest *productsRequest;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation StoreKitController
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance
|
||||||
|
{
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
static StoreKitController *instance;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[StoreKitController alloc] init];
|
||||||
|
});
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)purchaseProduct:(NSString *)productIdentifier
|
||||||
|
completion:(void (^)(BOOL success,
|
||||||
|
NSString *_Nullable transactionId,
|
||||||
|
NSString *_Nullable productId,
|
||||||
|
NSError *_Nullable error))completion
|
||||||
|
{
|
||||||
|
self.purchaseCompletion = completion;
|
||||||
|
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:productIdentifier]];
|
||||||
|
self.productsRequest.delegate = self;
|
||||||
|
[self.productsRequest start];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)restorePurchasesWithCompletion:(void (^)(BOOL success, NSError *_Nullable error))completion
|
||||||
|
{
|
||||||
|
self.restoreCompletion = completion;
|
||||||
|
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - SKProductsRequestDelegate
|
||||||
|
|
||||||
|
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
|
||||||
|
{
|
||||||
|
SKProduct *product = response.products.firstObject;
|
||||||
|
if (!product) {
|
||||||
|
if (self.purchaseCompletion) {
|
||||||
|
NSError *error = [NSError errorWithDomain:@"StoreKitController"
|
||||||
|
code:0
|
||||||
|
userInfo:@{ NSLocalizedDescriptionKey : @"Product not found" }];
|
||||||
|
self.purchaseCompletion(NO, nil, nil, error);
|
||||||
|
self.purchaseCompletion = nil;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SKPayment *payment = [SKPayment paymentWithProduct:product];
|
||||||
|
[[SKPaymentQueue defaultQueue] addPayment:payment];
|
||||||
|
self.productsRequest = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
|
||||||
|
{
|
||||||
|
if (self.purchaseCompletion) {
|
||||||
|
self.purchaseCompletion(NO, nil, nil, error);
|
||||||
|
self.purchaseCompletion = nil;
|
||||||
|
}
|
||||||
|
self.productsRequest = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - SKPaymentTransactionObserver
|
||||||
|
|
||||||
|
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
|
||||||
|
{
|
||||||
|
for (SKPaymentTransaction *transaction in transactions) {
|
||||||
|
switch (transaction.transactionState) {
|
||||||
|
case SKPaymentTransactionStatePurchased:
|
||||||
|
if (self.purchaseCompletion) {
|
||||||
|
self.purchaseCompletion(YES,
|
||||||
|
transaction.transactionIdentifier,
|
||||||
|
transaction.payment.productIdentifier,
|
||||||
|
nil);
|
||||||
|
self.purchaseCompletion = nil;
|
||||||
|
}
|
||||||
|
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||||
|
self.productsRequest = nil;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateFailed:
|
||||||
|
if (self.purchaseCompletion) {
|
||||||
|
self.purchaseCompletion(NO,
|
||||||
|
transaction.transactionIdentifier,
|
||||||
|
transaction.payment.productIdentifier,
|
||||||
|
transaction.error);
|
||||||
|
self.purchaseCompletion = nil;
|
||||||
|
}
|
||||||
|
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||||
|
self.productsRequest = nil;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateRestored: [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; break;
|
||||||
|
case SKPaymentTransactionStatePurchasing:
|
||||||
|
case SKPaymentTransactionStateDeferred: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
|
||||||
|
{
|
||||||
|
if (self.restoreCompletion) {
|
||||||
|
self.restoreCompletion(YES, nil);
|
||||||
|
self.restoreCompletion = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
|
||||||
|
{
|
||||||
|
if (self.restoreCompletion) {
|
||||||
|
self.restoreCompletion(NO, error);
|
||||||
|
self.restoreCompletion = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -2,6 +2,7 @@
|
||||||
#define IOS_CONTROLLER_H
|
#define IOS_CONTROLLER_H
|
||||||
|
|
||||||
#include "protocols/vpnprotocol.h"
|
#include "protocols/vpnprotocol.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
@ -54,6 +55,14 @@ public:
|
||||||
bool shareText(const QStringList &filesToSend);
|
bool shareText(const QStringList &filesToSend);
|
||||||
QString openFile();
|
QString openFile();
|
||||||
|
|
||||||
|
void purchaseProduct(const QString &productId,
|
||||||
|
std::function<void(bool success,
|
||||||
|
const QString &transactionId,
|
||||||
|
const QString &purchasedProductId,
|
||||||
|
const QString &errorString)> &&callback);
|
||||||
|
void restorePurchases(std::function<void(bool success,
|
||||||
|
const QString &errorString)> &&callback);
|
||||||
|
|
||||||
void requestInetAccess();
|
void requestInetAccess();
|
||||||
signals:
|
signals:
|
||||||
void connectionStateChanged(Vpn::ConnectionState state);
|
void connectionStateChanged(Vpn::ConnectionState state);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "../protocols/vpnprotocol.h"
|
#include "../protocols/vpnprotocol.h"
|
||||||
#import "ios_controller_wrapper.h"
|
#import "ios_controller_wrapper.h"
|
||||||
|
#import "StoreKitController.h"
|
||||||
|
|
||||||
const char* Action::start = "start";
|
const char* Action::start = "start";
|
||||||
const char* Action::restart = "restart";
|
const char* Action::restart = "restart";
|
||||||
|
@ -65,6 +66,9 @@ IosController::IosController() : QObject()
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
m_iosControllerWrapper = [[IosControllerWrapper alloc] initWithCppController:this];
|
m_iosControllerWrapper = [[IosControllerWrapper alloc] initWithCppController:this];
|
||||||
|
|
||||||
|
// Initialize StoreKitController early to start observing the payment queue
|
||||||
|
[StoreKitController sharedInstance];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
removeObserver: (__bridge NSObject *)m_iosControllerWrapper];
|
removeObserver: (__bridge NSObject *)m_iosControllerWrapper];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
@ -845,6 +849,50 @@ QString IosController::openFile() {
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IosController::purchaseProduct(const QString &productId,
|
||||||
|
std::function<void(bool success,
|
||||||
|
const QString &transactionId,
|
||||||
|
const QString &purchasedProductId,
|
||||||
|
const QString &errorString)> &&callback)
|
||||||
|
{
|
||||||
|
StoreKitController *controller = [StoreKitController sharedInstance];
|
||||||
|
[controller purchaseProduct:productId.toNSString() completion:^(BOOL s,
|
||||||
|
NSString * _Nullable transactionId,
|
||||||
|
NSString * _Nullable prodId,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
QString txId;
|
||||||
|
QString pId;
|
||||||
|
QString err;
|
||||||
|
if (transactionId) {
|
||||||
|
txId = QString::fromUtf8(transactionId.UTF8String);
|
||||||
|
}
|
||||||
|
if (prodId) {
|
||||||
|
pId = QString::fromUtf8(prodId.UTF8String);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
err = QString::fromUtf8(error.localizedDescription.UTF8String);
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
callback(s, txId, pId, err);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
void IosController::restorePurchases(std::function<void(bool success,
|
||||||
|
const QString &errorString)> &&callback)
|
||||||
|
{
|
||||||
|
StoreKitController *controller = [StoreKitController sharedInstance];
|
||||||
|
[controller restorePurchasesWithCompletion:^(BOOL s, NSError * _Nullable error) {
|
||||||
|
QString err;
|
||||||
|
if (error) {
|
||||||
|
err = QString::fromUtf8(error.localizedDescription.UTF8String);
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
callback(s, err);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
void IosController::requestInetAccess() {
|
void IosController::requestInetAccess() {
|
||||||
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
|
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
|
||||||
if (!url) {
|
if (!url) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue