@@ -3,32 +3,161 @@ module Language.Javascript.JSaddle.WKWebView
33 , jsaddleMainFile
44 , WKWebView(..)
55 , run
6+ , runWithAppConfig
67 , runFile
78 , mainBundleResourcePath
9+ , AppDelegateConfig (..)
10+ , AppDelegateNotificationConfig (..)
11+ , AuthorizationOption (..)
812 ) where
913
1014import Data.ByteString (ByteString)
15+import Data.Default (Default, def)
16+import Data.Set (Set)
17+import qualified Data.Set as Set
18+import Data.Word
19+import Foreign.Marshal.Utils (fromBool)
1120import Language.Javascript.JSaddle.WKWebView.Internal (jsaddleMain, jsaddleMainFile, WKWebView(..), mainBundleResourcePath)
1221import System.Environment (getProgName)
1322import Foreign.C.String (CString, withCString)
1423import Foreign.StablePtr (StablePtr, newStablePtr)
1524import Language.Javascript.JSaddle (JSM)
1625
17−foreign import ccall runInWKWebView :: StablePtr (WKWebView -> IO ()) -> CString -> IO ()
26+foreign import ccall runInWKWebView
27+ :: StablePtr (WKWebView -> IO ())
28+ -> CString
29+ -> StablePtr (IO ()) -- willFinishLaunchingWithOptions
30+ -> StablePtr (IO ()) -- didFinishLaunchingWithOptions
31+ -> StablePtr (IO ()) -- applicationDidBecomeActive
32+ -> StablePtr (IO ()) -- applicationWillResignActive
33+ -> StablePtr (IO ()) -- applicationDidEnterBackground
34+ -> StablePtr (IO ()) -- applicationWillEnterForeground
35+ -> StablePtr (IO ()) -- applicationWillTerminate
36+ -> StablePtr (IO ()) -- applicationSignificantTimeChange
37+ -> StablePtr (CString -> IO ()) -- applicationUniversalLink
38+ -> Word64 -- whether to run requestAuthorizationWithOptions
39+ -> Word64 -- Ask for Badge authorization
40+ -> Word64 -- Ask for Sound authorization
41+ -> Word64 -- Ask for Alert authorization
42+ -> Word64 -- Ask for CarPlay authorization
43+ -> Word64 -- registerForRemoteNotifications
44+ -> StablePtr (CString -> IO ()) -- didRegisterForRemoteNotificationsWithDeviceToken
45+ -> StablePtr (CString -> IO ()) -- didFailToRegisterForRemoteNotificationsWithError
46+ -> IO ()
47+
48+data AppDelegateConfig = AppDelegateConfig
49+ { _appDelegateConfig_willFinishLaunchingWithOptions :: IO ()
50+ , _appDelegateConfig_didFinishLaunchingWithOptions :: IO ()
51+ , _appDelegateConfig_applicationDidBecomeActive :: IO ()
52+ , _appDelegateConfig_applicationWillResignActive :: IO ()
53+ , _appDelegateConfig_applicationDidEnterBackground :: IO ()
54+ , _appDelegateConfig_applicationWillEnterForeground :: IO ()
55+ , _appDelegateConfig_applicationWillTerminate :: IO ()
56+ , _appDelegateConfig_applicationSignificantTimeChange :: IO ()
57+ , _appDelegateConfig_applicationUniversalLink :: CString -> IO ()
58+ , _appDelegateConfig_appDelegateNotificationConfig :: AppDelegateNotificationConfig
59+ }
60+
61+instance Default AppDelegateConfig where
62+ def = AppDelegateConfig
63+ { _appDelegateConfig_willFinishLaunchingWithOptions = return ()
64+ , _appDelegateConfig_didFinishLaunchingWithOptions = return ()
65+ , _appDelegateConfig_applicationDidBecomeActive = return ()
66+ , _appDelegateConfig_applicationWillResignActive = return ()
67+ , _appDelegateConfig_applicationDidEnterBackground = return ()
68+ , _appDelegateConfig_applicationWillEnterForeground = return ()
69+ , _appDelegateConfig_applicationWillTerminate = return ()
70+ , _appDelegateConfig_applicationSignificantTimeChange = return ()
71+ , _appDelegateConfig_applicationUniversalLink = \_ -> return ()
72+ , _appDelegateConfig_appDelegateNotificationConfig = def
73+ }
74+
75+data AuthorizationOption = AuthorizationOption_Badge
76+ | AuthorizationOption_Sound
77+ | AuthorizationOption_Alert
78+ | AuthorizationOption_CarPlay
79+ deriving (Show, Read, Eq, Ord)
80+
81+data AppDelegateNotificationConfig = AppDelegateNotificationConfig
82+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions :: Maybe (Set AuthorizationOption)
83+ , _appDelegateNotificationConfig_registerForRemoteNotifications :: Bool
84+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken :: CString -> IO ()
85+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError :: CString -> IO ()
86+ }
87+
88+instance Default AppDelegateNotificationConfig where
89+ def = AppDelegateNotificationConfig
90+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions = Nothing
91+ , _appDelegateNotificationConfig_registerForRemoteNotifications = False
92+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken = \_ -> return ()
93+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError = \_ -> return ()
94+ }
95+
1896
1997-- | Run JSaddle in a WKWebView
2098run :: JSM () -> IO ()
21−run f = do
22− handler <- newStablePtr (jsaddleMain f)
23− progName <- getProgName
24− withCString progName $ runInWKWebView handler
99+run = run' Nothing def
100+
101+-- | Run JSaddle in a WKWebView
102+runWithAppConfig :: AppDelegateConfig -> JSM () -> IO ()
103+runWithAppConfig = run' Nothing
25104
26105-- | Run JSaddle in a WKWebView first loading the specified file
27106-- from the mainBundle (relative to the resourcePath).
28107runFile :: ByteString -- ^ The file to navigate to.
29108 -> ByteString -- ^ The path to allow read access to.
30− -> JSM () -> IO ()
31−runFile url allowing f = do
32− handler <- newStablePtr (jsaddleMainFile url allowing f)
109+ -> AppDelegateConfig
110+ -> JSM ()
111+ -> IO ()
112+runFile url allowing = run' $ Just (url, allowing)
113+
114+run' :: Maybe (ByteString, ByteString)
115+ -> AppDelegateConfig
116+ -> JSM ()
117+ -> IO ()
118+run' mUrl cfg f = do
119+ handler <- case mUrl of
120+ Just (url, allowing) -> newStablePtr (jsaddleMainFile url allowing f)
121+ Nothing -> newStablePtr (jsaddleMain f)
33122 progName <- getProgName
34− withCString progName $ runInWKWebView handler
123+
124+ -- AppDelegate callbacks
125+ willFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_willFinishLaunchingWithOptions cfg
126+ didFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_didFinishLaunchingWithOptions cfg
127+ applicationDidBecomeActive <- newStablePtr $ _appDelegateConfig_applicationDidBecomeActive cfg
128+ applicationWillResignActive <- newStablePtr $ _appDelegateConfig_applicationWillResignActive cfg
129+ applicationDidEnterBackground <- newStablePtr $ _appDelegateConfig_applicationDidEnterBackground cfg
130+ applicationWillEnterForeground <- newStablePtr $ _appDelegateConfig_applicationWillEnterForeground cfg
131+ applicationWillTerminate <- newStablePtr $ _appDelegateConfig_applicationWillTerminate cfg
132+ applicationSignificantTimeChange <- newStablePtr $ _appDelegateConfig_applicationSignificantTimeChange cfg
133+ applicationUniversalLink <- newStablePtr $ _appDelegateConfig_applicationUniversalLink cfg
134+
135+ -- AppDelegate notification configuration
136+ let ncfg = _appDelegateConfig_appDelegateNotificationConfig cfg
137+ (requestAuthorizationWithOptions, authorizationOptions) =
138+ case _appDelegateNotificationConfig_requestAuthorizationWithOptions ncfg of
139+ Nothing -> (False, Set.empty)
140+ Just opts -> (True, opts)
141+ registerForRemoteNotifications = _appDelegateNotificationConfig_registerForRemoteNotifications ncfg
142+ didRegisterForRemoteNotificationsWithDeviceToken <- newStablePtr $ _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken ncfg
143+ didFailToRegisterForRemoteNotificationsWithError <- newStablePtr $ _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError ncfg
144+ withCString progName $ \pn -> runInWKWebView
145+ handler
146+ pn
147+ willFinishLaunchingWithOptions
148+ didFinishLaunchingWithOptions
149+ applicationDidBecomeActive
150+ applicationWillResignActive
151+ applicationDidEnterBackground
152+ applicationWillEnterForeground
153+ applicationWillTerminate
154+ applicationSignificantTimeChange
155+ applicationUniversalLink
156+ (fromBool requestAuthorizationWithOptions)
157+ (fromBool $ Set.member AuthorizationOption_Badge authorizationOptions)
158+ (fromBool $ Set.member AuthorizationOption_Sound authorizationOptions)
159+ (fromBool $ Set.member AuthorizationOption_Alert authorizationOptions)
160+ (fromBool $ Set.member AuthorizationOption_CarPlay authorizationOptions)
161+ (fromBool registerForRemoteNotifications)
162+ didRegisterForRemoteNotificationsWithDeviceToken
163+ didFailToRegisterForRemoteNotificationsWithError