@@ -3,32 +3,156 @@ 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+ -> Word64 -- whether to run requestAuthorizationWithOptions
38+ -> Word64 -- Ask for Badge authorization
39+ -> Word64 -- Ask for Sound authorization
40+ -> Word64 -- Ask for Alert authorization
41+ -> Word64 -- Ask for CarPlay authorization
42+ -> Word64 -- registerForRemoteNotifications
43+ -> StablePtr (CString -> IO ()) -- didRegisterForRemoteNotificationsWithDeviceToken
44+ -> StablePtr (CString -> IO ()) -- didFailToRegisterForRemoteNotificationsWithError
45+ -> IO ()
46+
47+data AppDelegateConfig = AppDelegateConfig
48+ { _appDelegateConfig_willFinishLaunchingWithOptions :: IO ()
49+ , _appDelegateConfig_didFinishLaunchingWithOptions :: IO ()
50+ , _appDelegateConfig_applicationDidBecomeActive :: IO ()
51+ , _appDelegateConfig_applicationWillResignActive :: IO ()
52+ , _appDelegateConfig_applicationDidEnterBackground :: IO ()
53+ , _appDelegateConfig_applicationWillEnterForeground :: IO ()
54+ , _appDelegateConfig_applicationWillTerminate :: IO ()
55+ , _appDelegateConfig_applicationSignificantTimeChange :: IO ()
56+ , _appDelegateConfig_appDelegateNotificationConfig :: AppDelegateNotificationConfig
57+ }
58+
59+instance Default AppDelegateConfig where
60+ def = AppDelegateConfig
61+ { _appDelegateConfig_willFinishLaunchingWithOptions = return ()
62+ , _appDelegateConfig_didFinishLaunchingWithOptions = return ()
63+ , _appDelegateConfig_applicationDidBecomeActive = return ()
64+ , _appDelegateConfig_applicationWillResignActive = return ()
65+ , _appDelegateConfig_applicationDidEnterBackground = return ()
66+ , _appDelegateConfig_applicationWillEnterForeground = return ()
67+ , _appDelegateConfig_applicationWillTerminate = return ()
68+ , _appDelegateConfig_applicationSignificantTimeChange = return ()
69+ , _appDelegateConfig_appDelegateNotificationConfig = def
70+ }
71+
72+data AuthorizationOption = AuthorizationOption_Badge
73+ | AuthorizationOption_Sound
74+ | AuthorizationOption_Alert
75+ | AuthorizationOption_CarPlay
76+ deriving (Show, Read, Eq, Ord)
77+
78+data AppDelegateNotificationConfig = AppDelegateNotificationConfig
79+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions :: Maybe (Set AuthorizationOption)
80+ , _appDelegateNotificationConfig_registerForRemoteNotifications :: Bool
81+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken :: CString -> IO ()
82+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError :: CString -> IO ()
83+ }
84+
85+instance Default AppDelegateNotificationConfig where
86+ def = AppDelegateNotificationConfig
87+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions = Nothing
88+ , _appDelegateNotificationConfig_registerForRemoteNotifications = False
89+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken = \_ -> return ()
90+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError = \_ -> return ()
91+ }
92+
1893
1994-- | Run JSaddle in a WKWebView
2095run :: JSM () -> IO ()
21−run f = do
22− handler <- newStablePtr (jsaddleMain f)
23− progName <- getProgName
24− withCString progName $ runInWKWebView handler
96+run = run' Nothing def
97+
98+-- | Run JSaddle in a WKWebView
99+runWithAppConfig :: AppDelegateConfig -> JSM () -> IO ()
100+runWithAppConfig = run' Nothing
25101
26102-- | Run JSaddle in a WKWebView first loading the specified file
27103-- from the mainBundle (relative to the resourcePath).
28104runFile :: ByteString -- ^ The file to navigate to.
29105 -> ByteString -- ^ The path to allow read access to.
30− -> JSM () -> IO ()
31−runFile url allowing f = do
32− handler <- newStablePtr (jsaddleMainFile url allowing f)
106+ -> AppDelegateConfig
107+ -> JSM ()
108+ -> IO ()
109+runFile url allowing = run' $ Just (url, allowing)
110+
111+run' :: Maybe (ByteString, ByteString)
112+ -> AppDelegateConfig
113+ -> JSM ()
114+ -> IO ()
115+run' mUrl cfg f = do
116+ handler <- case mUrl of
117+ Just (url, allowing) -> newStablePtr (jsaddleMainFile url allowing f)
118+ Nothing -> newStablePtr (jsaddleMain f)
33119 progName <- getProgName
34− withCString progName $ runInWKWebView handler
120+
121+ -- AppDelegate callbacks
122+ willFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_willFinishLaunchingWithOptions cfg
123+ didFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_didFinishLaunchingWithOptions cfg
124+ applicationDidBecomeActive <- newStablePtr $ _appDelegateConfig_applicationDidBecomeActive cfg
125+ applicationWillResignActive <- newStablePtr $ _appDelegateConfig_applicationWillResignActive cfg
126+ applicationDidEnterBackground <- newStablePtr $ _appDelegateConfig_applicationDidEnterBackground cfg
127+ applicationWillEnterForeground <- newStablePtr $ _appDelegateConfig_applicationWillEnterForeground cfg
128+ applicationWillTerminate <- newStablePtr $ _appDelegateConfig_applicationWillTerminate cfg
129+ applicationSignificantTimeChange <- newStablePtr $ _appDelegateConfig_applicationSignificantTimeChange cfg
130+
131+ -- AppDelegate notification configuration
132+ let ncfg = _appDelegateConfig_appDelegateNotificationConfig cfg
133+ (requestAuthorizationWithOptions, authorizationOptions) =
134+ case _appDelegateNotificationConfig_requestAuthorizationWithOptions ncfg of
135+ Nothing -> (False, Set.empty)
136+ Just opts -> (True, opts)
137+ registerForRemoteNotifications = _appDelegateNotificationConfig_registerForRemoteNotifications ncfg
138+ didRegisterForRemoteNotificationsWithDeviceToken <- newStablePtr $ _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken ncfg
139+ didFailToRegisterForRemoteNotificationsWithError <- newStablePtr $ _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError ncfg
140+ withCString progName $ \pn -> runInWKWebView
141+ handler
142+ pn
143+ willFinishLaunchingWithOptions
144+ didFinishLaunchingWithOptions
145+ applicationDidBecomeActive
146+ applicationWillResignActive
147+ applicationDidEnterBackground
148+ applicationWillEnterForeground
149+ applicationWillTerminate
150+ applicationSignificantTimeChange
151+ (fromBool requestAuthorizationWithOptions)
152+ (fromBool $ Set.member AuthorizationOption_Badge authorizationOptions)
153+ (fromBool $ Set.member AuthorizationOption_Sound authorizationOptions)
154+ (fromBool $ Set.member AuthorizationOption_Alert authorizationOptions)
155+ (fromBool $ Set.member AuthorizationOption_CarPlay authorizationOptions)
156+ (fromBool registerForRemoteNotifications)
157+ didRegisterForRemoteNotificationsWithDeviceToken
158+ didFailToRegisterForRemoteNotificationsWithError