2019-07-30 16:54:44 -07:00
//
// L a u n c h V i e w C o n t r o l l e r . s w i f t
// A l t S t o r e
//
// C r e a t e d b y R i l e y T e s t u t o n 7 / 3 0 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R i l e y T e s t u t . A l l r i g h t s r e s e r v e d .
//
import UIKit
import Roxas
2022-11-02 17:58:59 -07:00
import EmotionalDamage
import minimuxer
2019-07-30 16:54:44 -07:00
2020-09-03 16:39:08 -07:00
import AltStoreCore
2022-11-16 13:14:04 -07:00
import UniformTypeIdentifiers
2020-09-03 16:39:08 -07:00
2023-04-01 16:02:12 -07:00
let pairingFileName = " ALTPairingFile.mobiledevicepairing "
2023-01-04 09:52:12 -05:00
final class LaunchViewController : RSTLaunchViewController , UIDocumentPickerDelegate
2019-07-30 16:54:44 -07:00
{
2019-11-04 12:32:36 -08:00
private var didFinishLaunching = false
2020-01-13 13:53:04 -08:00
private var destinationViewController : UIViewController !
2019-07-30 16:54:44 -07:00
override var launchConditions : [ RSTLaunchCondition ] {
let isDatabaseStarted = RSTLaunchCondition ( condition : { DatabaseManager . shared . isStarted } ) { ( completionHandler ) in
DatabaseManager . shared . start ( completionHandler : completionHandler )
}
return [ isDatabaseStarted ]
}
2019-11-04 12:32:36 -08:00
override var childForStatusBarStyle : UIViewController ? {
return self . children . first
}
override var childForStatusBarHidden : UIViewController ? {
return self . children . first
}
2020-01-13 13:53:04 -08:00
override func viewDidLoad ( )
{
2022-11-08 14:15:09 -05:00
defer {
// C r e a t e d e s t i n a t i o n V i e w C o n t r o l l e r n o w s o v i e w c o n t r o l l e r s c a n r e g i s t e r f o r r e c e i v i n g N o t i f i c a t i o n s .
self . destinationViewController = self . storyboard ! . instantiateViewController ( withIdentifier : " tabBarController " ) as ! TabBarController
}
2020-01-13 13:53:04 -08:00
super . viewDidLoad ( )
2022-11-13 17:40:33 -08:00
}
override func viewDidAppear ( _ animated : Bool ) {
super . viewDidAppear ( true )
2023-01-04 09:32:04 -05:00
#if ! targetEnvironment ( simulator )
2022-11-08 14:15:09 -05:00
start_em_proxy ( bind_addr : Consts . Proxy . serverURL )
2022-11-02 17:58:59 -07:00
2022-11-08 14:15:09 -05:00
guard let pf = fetchPairingFile ( ) else {
2022-11-13 17:40:33 -08:00
displayError ( " Device pairing file not found. " )
2022-11-08 14:15:09 -05:00
return
}
2022-11-16 13:14:04 -07:00
start_minimuxer_threads ( pf )
2023-01-04 09:32:04 -05:00
#endif
2022-11-08 14:15:09 -05:00
}
func fetchPairingFile ( ) -> String ? {
let filename = " ALTPairingFile.mobiledevicepairing "
let fm = FileManager . default
let documentsPath = fm . documentsDirectory . appendingPathComponent ( " / \( filename ) " )
if fm . fileExists ( atPath : documentsPath . path ) , let contents = try ? String ( contentsOf : documentsPath ) , ! contents . isEmpty {
print ( " Loaded ALTPairingFile from \( documentsPath . path ) " )
return contents
} else if
let appResourcePath = Bundle . main . url ( forResource : " ALTPairingFile " , withExtension : " mobiledevicepairing " ) ,
fm . fileExists ( atPath : appResourcePath . path ) ,
let data = fm . contents ( atPath : appResourcePath . path ) ,
let contents = String ( data : data , encoding : . utf8 ) ,
! contents . isEmpty {
print ( " Loaded ALTPairingFile from \( appResourcePath . path ) " )
return contents
} else if let plistString = Bundle . main . object ( forInfoDictionaryKey : " ALTPairingFile " ) as ? String , ! plistString . isEmpty , ! plistString . contains ( " insert pairing file here " ) {
print ( " Loaded ALTPairingFile from Info.plist " )
return plistString
} else {
2022-11-16 13:14:04 -07:00
// S h o w a n a l e r t e x p l a i n i n g t h e p a i r i n g f i l e
// C r e a t e n e w A l e r t
2023-02-15 21:14:51 -08:00
let dialogMessage = UIAlertController ( title : " Pairing File " , message : " Select the pairing file for your device. For more information, go to https://wiki.sidestore.io/guides/install#pairing-process " , preferredStyle : . alert )
2022-11-16 13:14:04 -07:00
// C r e a t e O K b u t t o n w i t h a c t i o n h a n d l e r
let ok = UIAlertAction ( title : " OK " , style : . default , handler : { ( action ) -> Void in
// T r y t o l o a d i t f r o m a f i l e p i c k e r
var types = UTType . types ( tag : " plist " , tagClass : UTTagClass . filenameExtension , conformingTo : nil )
2022-12-17 21:13:53 +00:00
types . append ( contentsOf : UTType . types ( tag : " mobiledevicepairing " , tagClass : UTTagClass . filenameExtension , conformingTo : UTType . data ) )
types . append ( . xml )
2022-11-16 13:14:04 -07:00
let documentPickerController = UIDocumentPickerViewController ( forOpeningContentTypes : types )
2022-12-03 17:24:07 -05:00
documentPickerController . shouldShowFileExtensions = true
2022-11-16 13:14:04 -07:00
documentPickerController . delegate = self
self . present ( documentPickerController , animated : true , completion : nil )
} )
// A d d O K b u t t o n t o a d i a l o g m e s s a g e
dialogMessage . addAction ( ok )
// P r e s e n t A l e r t t o
self . present ( dialogMessage , animated : true , completion : nil )
2022-11-08 14:15:09 -05:00
return nil
}
}
2022-11-16 16:41:02 -05:00
2022-11-08 14:15:09 -05:00
func displayError ( _ msg : String ) {
2022-11-13 17:40:33 -08:00
print ( msg )
// C r e a t e a n e w a l e r t
let dialogMessage = UIAlertController ( title : " Error launching SideStore " , message : msg , preferredStyle : . alert )
// P r e s e n t a l e r t t o u s e r
self . present ( dialogMessage , animated : true , completion : nil )
2020-01-13 13:53:04 -08:00
}
2022-11-16 13:14:04 -07:00
func documentPicker ( _ controller : UIDocumentPickerViewController , didPickDocumentsAt urls : [ URL ] ) {
let url = urls [ 0 ]
let isSecuredURL = url . startAccessingSecurityScopedResource ( ) = = true
do {
// R e a d t o a s t r i n g
let data1 = try Data ( contentsOf : urls [ 0 ] )
let pairing_string = String ( bytes : data1 , encoding : . utf8 )
if pairing_string = = nil {
displayError ( " Unable to read pairing file " )
}
// S a v e t o a f i l e f o r n e x t l a u n c h
2023-04-01 16:02:12 -07:00
let pairingFile = FileManager . default . documentsDirectory . appendingPathComponent ( " \( pairingFileName ) " )
try pairing_string ? . write ( to : pairingFile , atomically : true , encoding : String . Encoding . utf8 )
2022-11-16 13:14:04 -07:00
// S t a r t m i n i m u x e r n o w t h a t w e h a v e a f i l e
start_minimuxer_threads ( pairing_string ! )
} catch {
displayError ( " Unable to read pairing file " )
}
if ( isSecuredURL ) {
url . stopAccessingSecurityScopedResource ( )
}
controller . dismiss ( animated : true , completion : nil )
}
func documentPickerWasCancelled ( _ controller : UIDocumentPickerViewController ) {
2022-12-17 21:13:53 +00:00
displayError ( " Choosing a pairing file was cancelled. Please re-open the app and try again. " )
2022-11-16 13:14:04 -07:00
}
func start_minimuxer_threads ( _ pairing_file : String ) {
2023-04-01 16:02:12 -07:00
target_minimuxer_address ( )
let documentsDirectory = FileManager . default . documentsDirectory . absoluteString
do {
try start ( pairing_file , documentsDirectory )
} catch {
try ! FileManager . default . removeItem ( at : FileManager . default . documentsDirectory . appendingPathComponent ( " \( pairingFileName ) " ) )
2023-04-11 21:04:07 -07:00
displayError ( " minimuxer failed to start, please restart SideStore. \( ( error as ? LocalizedError ) ? . failureReason ? ? " UNKNOWN ERROR!!!!!! REPORT TO GITHUB ISSUES! " ) " )
2022-11-16 13:14:04 -07:00
}
2023-10-20 21:43:51 -04:00
if #available ( iOS 17 , * ) {
// TODO: i O S 1 7 a n d a b o v e h a v e a n e w J I T i m p l e m e n t a t i o n t h a t i s c o m p l e t e l y b r o k e n i n S i d e S t o r e : (
}
else {
start_auto_mounter ( documentsDirectory )
}
2022-11-16 13:14:04 -07:00
}
2019-07-30 16:54:44 -07:00
}
extension LaunchViewController
{
override func handleLaunchError ( _ error : Error )
{
do
{
throw error
}
catch let error as NSError
{
2022-11-05 23:50:07 -07:00
let title = error . userInfo [ NSLocalizedFailureErrorKey ] as ? String ? ? NSLocalizedString ( " Unable to Launch SideStore " , comment : " " )
2019-07-30 16:54:44 -07:00
2022-09-20 13:19:17 -05:00
let errorDescription : String
if #available ( iOS 14.5 , * )
{
let errorMessages = [ error . debugDescription ] + error . underlyingErrors . map { ( $0 as NSError ) . debugDescription }
errorDescription = errorMessages . joined ( separator : " \n \n " )
}
else
{
errorDescription = error . debugDescription
}
let alertController = UIAlertController ( title : title , message : errorDescription , preferredStyle : . alert )
2019-07-30 16:54:44 -07:00
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Retry " , comment : " " ) , style : . default , handler : { ( action ) in
self . handleLaunchConditions ( )
} ) )
self . present ( alertController , animated : true , completion : nil )
}
}
override func finishLaunching ( )
{
super . finishLaunching ( )
2019-11-04 12:32:36 -08:00
guard ! self . didFinishLaunching else { return }
2019-07-30 16:54:44 -07:00
AppManager . shared . update ( )
2022-04-14 17:39:43 -07:00
AppManager . shared . updatePatronsIfNeeded ( )
2019-08-28 11:13:22 -07:00
PatreonAPI . shared . refreshPatreonAccount ( )
2019-07-30 16:54:44 -07:00
2019-11-04 12:32:36 -08:00
// A d d v i e w c o n t r o l l e r a s c h i l d ( r a t h e r t h a n p r e s e n t i n g m o d a l l y )
// s o t i n t a d j u s t m e n t + c a r d p r e s e n t a t i o n s w o r k s c o r r e c t l y .
2020-01-13 13:53:04 -08:00
self . destinationViewController . view . frame = CGRect ( x : 0 , y : 0 , width : self . view . bounds . width , height : self . view . bounds . height )
self . destinationViewController . view . alpha = 0.0
self . addChild ( self . destinationViewController )
self . view . addSubview ( self . destinationViewController . view , pinningEdgesWith : . zero )
self . destinationViewController . didMove ( toParent : self )
2019-11-04 12:32:36 -08:00
UIView . animate ( withDuration : 0.2 ) {
2020-01-13 13:53:04 -08:00
self . destinationViewController . view . alpha = 1.0
2019-11-04 12:32:36 -08:00
}
self . didFinishLaunching = true
2019-07-30 16:54:44 -07:00
}
}