Automatic updates

This commit is contained in:
Ali 2020-02-11 17:42:54 +01:00
parent cae526172f
commit 677b91f350
6 changed files with 96 additions and 51 deletions

View File

@ -2,7 +2,7 @@
def appConfig(): def appConfig():
apiId = native.read_config("custom", "apiId") apiId = native.read_config("custom", "apiId")
apiHash = native.read_config("custom", "apiHash") apiHash = native.read_config("custom", "apiHash")
hockeyAppId = native.read_config("custom", "hockeyAppId") appCenterId = native.read_config("custom", "appCenterId")
isInternalBuild = native.read_config("custom", "isInternalBuild") isInternalBuild = native.read_config("custom", "isInternalBuild")
isAppStoreBuild = native.read_config("custom", "isAppStoreBuild") isAppStoreBuild = native.read_config("custom", "isAppStoreBuild")
appStoreId = native.read_config("custom", "appStoreId") appStoreId = native.read_config("custom", "appStoreId")
@ -11,7 +11,7 @@ def appConfig():
return { return {
"apiId": apiId, "apiId": apiId,
"apiHash": apiHash, "apiHash": apiHash,
"hockeyAppId": hockeyAppId, "appCenterId": appCenterId,
"isInternalBuild": isInternalBuild, "isInternalBuild": isInternalBuild,
"isAppStoreBuild": isAppStoreBuild, "isAppStoreBuild": isAppStoreBuild,
"appStoreId": appStoreId, "appStoreId": appStoreId,

View File

@ -10,7 +10,7 @@ BUCK_OPTIONS=\
--config custom.baseApplicationBundleId="${BUNDLE_ID}" \ --config custom.baseApplicationBundleId="${BUNDLE_ID}" \
--config custom.apiId="${API_ID}" \ --config custom.apiId="${API_ID}" \
--config custom.apiHash="${API_HASH}" \ --config custom.apiHash="${API_HASH}" \
--config custom.hockeyAppId="${HOCKEYAPP_ID}" \ --config custom.appCenterId="${APP_CENTER_ID}" \
--config custom.isInternalBuild="${IS_INTERNAL_BUILD}" \ --config custom.isInternalBuild="${IS_INTERNAL_BUILD}" \
--config custom.isAppStoreBuild="${IS_APPSTORE_BUILD}" \ --config custom.isAppStoreBuild="${IS_APPSTORE_BUILD}" \
--config custom.appStoreId="${APPSTORE_ID}" \ --config custom.appStoreId="${APPSTORE_ID}" \

View File

@ -9,7 +9,7 @@ static_library(
compiler_flags = [ compiler_flags = [
'-DAPP_CONFIG_API_ID=' + appConfig()["apiId"], '-DAPP_CONFIG_API_ID=' + appConfig()["apiId"],
'-DAPP_CONFIG_API_HASH="' + appConfig()["apiHash"] + '"', '-DAPP_CONFIG_API_HASH="' + appConfig()["apiHash"] + '"',
'-DAPP_CONFIG_HOCKEYAPP_ID="' + appConfig()["hockeyAppId"] + '"', '-DAPP_CONFIG_APP_CENTER_ID="' + appConfig()["appCenterId"] + '"',
'-DAPP_CONFIG_IS_INTERNAL_BUILD=' + appConfig()["isInternalBuild"], '-DAPP_CONFIG_IS_INTERNAL_BUILD=' + appConfig()["isInternalBuild"],
'-DAPP_CONFIG_IS_APPSTORE_BUILD=' + appConfig()["isAppStoreBuild"], '-DAPP_CONFIG_IS_APPSTORE_BUILD=' + appConfig()["isAppStoreBuild"],
'-DAPP_CONFIG_APPSTORE_ID=' + appConfig()["appStoreId"], '-DAPP_CONFIG_APPSTORE_ID=' + appConfig()["appStoreId"],

View File

@ -11,7 +11,7 @@
- (instancetype _Nonnull)initWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId; - (instancetype _Nonnull)initWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId;
@property (nonatomic, strong, readonly) NSString * _Nullable hockeyAppId; @property (nonatomic, strong, readonly) NSString * _Nullable appCenterId;
@property (nonatomic, readonly) int32_t apiId; @property (nonatomic, readonly) int32_t apiId;
@property (nonatomic, strong, readonly) NSString * _Nonnull apiHash; @property (nonatomic, strong, readonly) NSString * _Nonnull apiHash;
@property (nonatomic, readonly) bool isInternalBuild; @property (nonatomic, readonly) bool isInternalBuild;

View File

@ -72,7 +72,7 @@ API_AVAILABLE(ios(10))
NSData * _Nullable _bundleData; NSData * _Nullable _bundleData;
int32_t _apiId; int32_t _apiId;
NSString * _Nonnull _apiHash; NSString * _Nonnull _apiHash;
NSString * _Nullable _hockeyAppId; NSString * _Nullable _appCenterId;
NSMutableDictionary * _Nonnull _dataDict; NSMutableDictionary * _Nonnull _dataDict;
} }
@ -129,7 +129,7 @@ API_AVAILABLE(ios(10))
if (self != nil) { if (self != nil) {
_apiId = APP_CONFIG_API_ID; _apiId = APP_CONFIG_API_ID;
_apiHash = @(APP_CONFIG_API_HASH); _apiHash = @(APP_CONFIG_API_HASH);
_hockeyAppId = @(APP_CONFIG_HOCKEYAPP_ID); _appCenterId = @(APP_CONFIG_APP_CENTER_ID);
_dataDict = [[NSMutableDictionary alloc] init]; _dataDict = [[NSMutableDictionary alloc] init];
@ -163,8 +163,8 @@ API_AVAILABLE(ios(10))
return _apiHash; return _apiHash;
} }
- (NSString * _Nullable)hockeyAppId { - (NSString * _Nullable)appCenterId {
return _hockeyAppId; return _appCenterId;
} }
- (bool)isInternalBuild { - (bool)isInternalBuild {

View File

@ -5,7 +5,6 @@ import TelegramCore
import SyncCore import SyncCore
import UserNotifications import UserNotifications
import Intents import Intents
//import HockeySDK
import Postbox import Postbox
import PushKit import PushKit
import AsyncDisplayKit import AsyncDisplayKit
@ -157,12 +156,13 @@ final class SharedApplicationContext {
} }
} }
@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate/*, BITHockeyManagerDelegate*/, UNUserNotificationCenterDelegate, UIAlertViewDelegate { @objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate, UIAlertViewDelegate {
@objc var window: UIWindow? @objc var window: UIWindow?
var nativeWindow: (UIWindow & WindowHost)? var nativeWindow: (UIWindow & WindowHost)?
var mainWindow: Window1! var mainWindow: Window1!
private var dataImportSplash: LegacyDataImportSplash? private var dataImportSplash: LegacyDataImportSplash?
private var buildConfig: BuildConfig?
let episodeId = arc4random() let episodeId = arc4random()
private let isInForegroundPromise = ValuePromise<Bool>(false, ignoreRepeated: true) private let isInForegroundPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -369,6 +369,7 @@ final class SharedApplicationContext {
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName) let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId) let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
self.buildConfig = buildConfig
let signatureDict = BuildConfigExtra.signatureDict() let signatureDict = BuildConfigExtra.signatureDict()
let apiId: Int32 = buildConfig.apiId let apiId: Int32 = buildConfig.apiId
@ -1338,46 +1339,6 @@ final class SharedApplicationContext {
self.isActivePromise.set(true) self.isActivePromise.set(true)
} }
/*BITHockeyBaseManager.setPresentAlert({ [weak self] alert in
if let strongSelf = self, let alert = alert {
var actions: [TextAlertAction] = []
for action in alert.actions {
let isDefault = action.style == .default
actions.append(TextAlertAction(type: isDefault ? .defaultAction : .genericAction, title: action.title ?? "", action: {
if let action = action as? BITAlertAction {
action.invokeAction()
}
}))
}
if let sharedContext = strongSelf.contextValue?.context.sharedContext {
let presentationData = sharedContext.currentPresentationData.with { $0 }
strongSelf.mainWindow.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: alert.title, text: alert.message ?? "", actions: actions), on: .root)
}
}
})
BITHockeyBaseManager.setPresentView({ [weak self] controller in
if let strongSelf = self, let controller = controller {
let parent = LegacyController(presentation: .modal(animateIn: true), theme: nil)
let navigationController = UINavigationController(rootViewController: controller)
controller.navigation_setDismiss({ [weak parent] in
parent?.dismiss()
}, rootController: nil)
parent.bind(controller: navigationController)
strongSelf.mainWindow.present(parent, on: .root)
}
})
if let hockeyAppId = buildConfig.hockeyAppId, !hockeyAppId.isEmpty {
BITHockeyManager.shared().configure(withIdentifier: hockeyAppId, delegate: self)
BITHockeyManager.shared().crashManager.crashManagerStatus = .alwaysAsk
BITHockeyManager.shared().start()
#if targetEnvironment(simulator)
#else
BITHockeyManager.shared().authenticator.authenticateInstallation()
#endif
}*/
if UIApplication.shared.isStatusBarHidden { if UIApplication.shared.isStatusBarHidden {
UIApplication.shared.setStatusBarHidden(false, with: .none) UIApplication.shared.setStatusBarHidden(false, with: .none)
} }
@ -1403,6 +1364,8 @@ final class SharedApplicationContext {
}) })
}*/ }*/
self.maybeCheckForUpdates()
return true return true
} }
@ -1486,6 +1449,8 @@ final class SharedApplicationContext {
self.isInForegroundPromise.set(true) self.isInForegroundPromise.set(true)
self.isActiveValue = true self.isActiveValue = true
self.isActivePromise.set(true) self.isActivePromise.set(true)
self.maybeCheckForUpdates()
} }
func applicationWillTerminate(_ application: UIApplication) { func applicationWillTerminate(_ application: UIApplication) {
@ -2204,6 +2169,60 @@ final class SharedApplicationContext {
completionHandler() completionHandler()
} }
private var lastCheckForUpdatesTimestamp: Double?
private let currentCheckForUpdatesDisposable = MetaDisposable()
private func maybeCheckForUpdates() {
#if targetEnvironment(simulator)
return;
#endif
guard let buildConfig = self.buildConfig, !buildConfig.isAppStoreBuild, let appCenterId = buildConfig.appCenterId, !appCenterId.isEmpty else {
return
}
let timestamp = CFAbsoluteTimeGetCurrent()
if self.lastCheckForUpdatesTimestamp == nil || self.lastCheckForUpdatesTimestamp! < timestamp - 10.0 * 60.0 {
self.lastCheckForUpdatesTimestamp = timestamp
if let url = URL(string: "https://api.appcenter.ms/v0.1/public/sdk/apps/\(appCenterId)/releases/latest") {
self.currentCheckForUpdatesDisposable.set((downloadHTTPData(url: url)
|> deliverOnMainQueue).start(next: { [weak self] data in
guard let strongSelf = self else {
return
}
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else {
return
}
guard let dict = json as? [String: Any] else {
return
}
guard let versionString = dict["version"] as? String, let version = Int(versionString) else {
return
}
guard let releaseNotesUrl = dict["release_notes_url"] as? String else {
return
}
guard let currentVersionString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String, let currentVersion = Int(currentVersionString) else {
return
}
if currentVersion < version {
let _ = (strongSelf.sharedContextPromise.get()
|> take(1)
|> deliverOnMainQueue).start(next: { sharedContext in
let presentationData = sharedContext.sharedContext.currentPresentationData.with { $0 }
sharedContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "A new build is available", actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .defaultAction, title: "Show", action: {
sharedContext.sharedContext.applicationBindings.openUrl(releaseNotesUrl)
})
]), on: .root, blockInteraction: false, completion: {})
})
}
}))
}
}
}
override var next: UIResponder? { override var next: UIResponder? {
if let context = self.contextValue, let controller = context.context.keyShortcutsController { if let context = self.contextValue, let controller = context.context.keyShortcutsController {
return controller return controller
@ -2345,3 +2364,29 @@ private func messageIdFromNotification(peerId: PeerId, notification: UNNotificat
} }
return nil return nil
} }
private enum DownloadFileError {
case network
}
private func downloadHTTPData(url: URL) -> Signal<Data, DownloadFileError> {
return Signal { subscriber in
let completed = Atomic<Bool>(value: false)
let downloadTask = URLSession.shared.downloadTask(with: url, completionHandler: { location, _, error in
let _ = completed.swap(true)
if let location = location, let data = try? Data(contentsOf: location) {
subscriber.putNext(data)
subscriber.putCompletion()
} else {
subscriber.putError(.network)
}
})
downloadTask.resume()
return ActionDisposable {
if !completed.with({ $0 }) {
downloadTask.cancel()
}
}
}
}