on master help sign in
Merge wkwebview-appdelegate-cabal-flag
commitaa06e8fbc9cc14e62c54657be12774a1e0d55fb2 authorHamish Mackenzie <Hamish.K.Mackenzie@googlemail.com> dateSat 13 May 2017, 13:07 (9 years ago) parent0a2cfc6
6 files changed+273−26
jsaddle-wkwebview/cbits-uikit/AppDelegate.m+109−2 jsaddle-wkwebview/cbits-uikit/ViewController.m+2−2 jsaddle-wkwebview/default.nix+2−2 jsaddle-wkwebview/jsaddle-wkwebview.cabal+15−7 jsaddle-wkwebview/src-ghc/Language/Javascript/JSaddle/WKWebView.hs+129−10 jsaddle-wkwebview/src/Language/Javascript/JSaddle/WKWebView/Internal.hs+16−3
jsaddle-wkwebview/cbits-uikit/AppDelegate.m+109−2
@@ -1,55 +1,162 @@
11#import "AppDelegate.h"
22#import "ViewController.h"
3+#import <UserNotifications/UserNotifications.h>
4+#import <stdint.h>
35
4−@interface AppDelegate ()
6+extern void callIO(HsStablePtr);
7+extern void callWithCString(const char * _Nonnull, HsStablePtr);
58
9+@interface AppDelegate ()
610
711@end
812
913HsStablePtr globalHandler = 0;
14+HsStablePtr global_willFinishLaunchingWithOptions = 0;
15+HsStablePtr global_didFinishLaunchingWithOptions = 0;
16+HsStablePtr global_applicationDidBecomeActive = 0;
17+HsStablePtr global_applicationWillResignActive = 0;
18+HsStablePtr global_applicationDidEnterBackground = 0;
19+HsStablePtr global_applicationWillEnterForeground = 0;
20+HsStablePtr global_applicationWillTerminate = 0;
21+HsStablePtr global_applicationSignificantTimeChange = 0;
22+uint64_t global_requestAuthorizationWithOptions = 0;
23+uint64_t global_requestAuthorizationOptionBadge = 0;
24+uint64_t global_requestAuthorizationOptionSound = 0;
25+uint64_t global_requestAuthorizationOptionAlert = 0;
26+uint64_t global_requestAuthorizationOptionCarPlay = 0;
27+uint64_t global_registerForRemoteNotifications = 0;
28+HsStablePtr global_didRegisterForRemoteNotificationsWithDeviceToken = 0;
29+HsStablePtr global_didFailToRegisterForRemoteNotificationsWithError = 0;
1030
1131@implementation AppDelegate
1232
33+- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
34+ // Tells the delegate that the launch process has begun but that state restoration has not yet occurred.
35+ callIO(global_willFinishLaunchingWithOptions);
36+ return YES;
37+}
38+
1339- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
40+ // Tells the delegate that the launch process is almost done and the app is almost ready to run.
1441 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
1542 // Override point for customization after application launch.
1643 self.window.rootViewController = [[ViewController alloc] initWithHandler:globalHandler];
1744 self.window.backgroundColor = [UIColor whiteColor];
1845 [self.window makeKeyAndVisible];
46+ UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
47+ center.delegate = self;
48+ if (global_requestAuthorizationWithOptions) {
49+ UNAuthorizationOptions options = (UNAuthorizationOptions)0;
50+ if (global_requestAuthorizationOptionBadge) {
51+ options = options | UNAuthorizationOptionBadge;
52+ }
53+ if (global_requestAuthorizationOptionSound) {
54+ options = options | UNAuthorizationOptionSound;
55+ }
56+ if (global_requestAuthorizationOptionAlert) {
57+ options = options | UNAuthorizationOptionAlert;
58+ }
59+ if (global_requestAuthorizationOptionCarPlay) {
60+ options = options | UNAuthorizationOptionCarPlay;
61+ }
62+ [center requestAuthorizationWithOptions:(options)
63+ completionHandler:^(BOOL granted, NSError * _Nullable error) {
64+ // Handler used to alter application behavior based on types of notifications authorized
65+ }];
66+ if (global_registerForRemoteNotifications) {
67+ [application registerForRemoteNotifications];
68+ }
69+ }
70+ callIO(global_didFinishLaunchingWithOptions);
1971 return YES;
2072}
2173
2274- (void)applicationWillResignActive:(UIApplication *)application {
2375 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
2476 // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
77+ callIO(global_applicationWillResignActive);
2578}
2679
2780
2881- (void)applicationDidEnterBackground:(UIApplication *)application {
2982 // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
3083 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
84+ callIO(global_applicationDidEnterBackground);
3185}
3286
3387
3488- (void)applicationWillEnterForeground:(UIApplication *)application {
3589 // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
90+ callIO(global_applicationWillEnterForeground);
3691}
3792
3893
3994- (void)applicationDidBecomeActive:(UIApplication *)application {
4095 // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
96+ callIO(global_applicationDidBecomeActive);
4197}
4298
4399
44100- (void)applicationWillTerminate:(UIApplication *)application {
45101 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
102+ callIO(global_applicationWillTerminate);
103+}
104+
105+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
106+ // Tells the delegate that the app successfully registered with Apple Push Notification service (APNs).
107+ NSString *deviceTokenString = [deviceToken base64EncodedStringWithOptions: 0];
108+ callWithCString([deviceTokenString UTF8String], global_didRegisterForRemoteNotificationsWithDeviceToken);
109+}
110+
111+- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
112+ // Sent to the delegate when Apple Push Notification service cannot successfully complete the registration process.
113+ NSString *errorString = [error localizedDescription];
114+ callWithCString([errorString UTF8String], global_didFailToRegisterForRemoteNotificationsWithError);
115+}
116+
117+- (void)applicationSignificantTimeChange:(UIApplication *)application {
118+ // Tells the delegate when there is a significant change in the time.
119+ callIO(global_applicationSignificantTimeChange);
46120}
47121
48122@end
49123
50−void runInWKWebView(HsStablePtr handler, const char * _Nonnull progName) {
124+void runInWKWebView(HsStablePtr handler,
125+ const char * _Nonnull progName,
126+ HsStablePtr hs_willFinishLaunchingWithOptions,
127+ HsStablePtr hs_didFinishLaunchingWithOptions,
128+ HsStablePtr hs_applicationDidBecomeActive,
129+ HsStablePtr hs_applicationWillResignActive,
130+ HsStablePtr hs_applicationDidEnterBackground,
131+ HsStablePtr hs_applicationWillEnterForeground,
132+ HsStablePtr hs_applicationWillTerminate,
133+ HsStablePtr hs_applicationSignificantTimeChange,
134+ const uint64_t hs_requestAuthorizationWithOptions,
135+ const uint64_t hs_requestAuthorizationOptionBadge,
136+ const uint64_t hs_requestAuthorizationOptionSound,
137+ const uint64_t hs_requestAuthorizationOptionAlert,
138+ const uint64_t hs_requestAuthorizationOptionCarPlay,
139+ const uint64_t hs_registerForRemoteNotifications,
140+ HsStablePtr hs_didRegisterForRemoteNotificationsWithDeviceToken,
141+ HsStablePtr hs_didFailToRegisterForRemoteNotificationsWithError) {
51142 @autoreleasepool {
52143 globalHandler = handler;
144+ global_willFinishLaunchingWithOptions = hs_willFinishLaunchingWithOptions;
145+ global_didFinishLaunchingWithOptions = hs_didFinishLaunchingWithOptions;
146+ global_applicationDidBecomeActive = hs_applicationDidBecomeActive;
147+ global_applicationWillResignActive = hs_applicationWillResignActive;
148+ global_applicationDidEnterBackground = hs_applicationDidEnterBackground;
149+ global_applicationWillEnterForeground = hs_applicationWillEnterForeground;
150+ global_applicationWillTerminate = hs_applicationWillTerminate;
151+ global_applicationSignificantTimeChange = hs_applicationSignificantTimeChange;
152+ global_requestAuthorizationWithOptions = hs_requestAuthorizationWithOptions;
153+ global_requestAuthorizationOptionBadge = hs_requestAuthorizationOptionBadge;
154+ global_requestAuthorizationOptionSound = hs_requestAuthorizationOptionSound;
155+ global_requestAuthorizationOptionAlert = hs_requestAuthorizationOptionAlert;
156+ global_requestAuthorizationOptionCarPlay = hs_requestAuthorizationOptionCarPlay;
157+ global_registerForRemoteNotifications = hs_registerForRemoteNotifications;
158+ global_didRegisterForRemoteNotificationsWithDeviceToken = hs_didRegisterForRemoteNotificationsWithDeviceToken;
159+ global_didFailToRegisterForRemoteNotificationsWithError = hs_didFailToRegisterForRemoteNotificationsWithError;
53160 const char * _Nonnull argv [] = {"", 0};
54161 UIApplicationMain(0, argv, nil, NSStringFromClass([AppDelegate class]));
55162 }
jsaddle-wkwebview/cbits-uikit/ViewController.m+2−2
@@ -1,6 +1,6 @@
11#import "ViewController.h"
22
3−extern void withWebView(WKWebView *, HsStablePtr);
3+extern void callWithWebView(WKWebView *, HsStablePtr);
44
55@interface ViewController ()
66
@@ -27,7 +27,7 @@ extern void withWebView(WKWebView *, HsStablePtr);
2727
2828- (void)viewDidLoad {
2929 [super viewDidLoad];
30− withWebView(_webView, _handler);
30+ callWithWebView(_webView, _handler);
3131}
3232
3333
jsaddle-wkwebview/default.nix+2−2
@@ -1,4 +1,4 @@
1−{ mkDerivation, stdenv, aeson, base, bytestring, jsaddle
1+{ mkDerivation, stdenv, aeson, base, bytestring, jsaddle, data-default
22, buildPackages
33}:
44
@@ -6,7 +6,7 @@ mkDerivation {
66 pname = "jsaddle-wkwebview";
77 version = "0.8.3.2";
88 src = ./.;
9− libraryHaskellDepends = [ aeson base bytestring jsaddle ]
9+ libraryHaskellDepends = [ aeson base bytestring jsaddle data-default ]
1010 # should use `librarySystemDepends` but it is not propagated
1111 ++ (with buildPackages; [
1212 darwin.libobjc
jsaddle-wkwebview/jsaddle-wkwebview.cabal+15−7
@@ -14,6 +14,10 @@ description:
1414category: Web, Javascript
1515author: Hamish Mackenzie
1616
17+flag include-app-delegate
18+ description: Include default AppDelegate C sources.
19+ default: True
20+
1721source-repository head
1822 type: git
1923 location: https://github.com/ghcjs/jsaddle
@@ -26,7 +30,9 @@ library
2630 aeson >=0.8.0.2 && <1.3,
2731 base <5,
2832 bytestring >=0.10.6.0 && <0.11,
29− jsaddle >= 0.8.0.0 && <0.9
33+ jsaddle >= 0.8.0.0 && <0.9,
34+ data-default,
35+ containers
3036 default-language: Haskell2010
3137 hs-source-dirs: src
3238 frameworks: Foundation, WebKit
@@ -38,11 +44,13 @@ library
3844 else
3945 hs-source-dirs: src-ghc
4046 if os(ios)
41− frameworks: UIKit
42− c-sources:
43− cbits-uikit/AppDelegate.m
44− cbits-uikit/ViewController.m
47+ frameworks: UIKit, UserNotifications
48+ if flag(include-app-delegate)
49+ c-sources:
50+ cbits-uikit/AppDelegate.m
51+ cbits-uikit/ViewController.m
4552 else
4653 frameworks: Cocoa
47− c-sources:
48− cbits-cocoa/AppDelegate.m
54+ if flag(include-app-delegate)
55+ c-sources:
56+ cbits-cocoa/AppDelegate.m
jsaddle-wkwebview/src-ghc/Language/Javascript/JSaddle/WKWebView.hs+129−10
@@ -5,30 +5,149 @@ module Language.Javascript.JSaddle.WKWebView
55 , run
66 , runFile
77 , mainBundleResourcePath
8+ , AppDelegateConfig (..)
9+ , AppDelegateNotificationConfig (..)
10+ , AuthorizationOption (..)
811 ) where
912
1013import Data.ByteString (ByteString)
14+import Data.Default (Default, def)
15+import Data.Set (Set)
16+import qualified Data.Set as Set
17+import Data.Word
18+import Foreign.Marshal.Utils (fromBool)
1119import Language.Javascript.JSaddle.WKWebView.Internal (jsaddleMain, jsaddleMainFile, WKWebView(..), mainBundleResourcePath)
1220import System.Environment (getProgName)
1321import Foreign.C.String (CString, withCString)
1422import Foreign.StablePtr (StablePtr, newStablePtr)
1523import Language.Javascript.JSaddle (JSM)
1624
17−foreign import ccall runInWKWebView :: StablePtr (WKWebView -> IO ()) -> CString -> IO ()
25+foreign import ccall runInWKWebView
26+ :: StablePtr (WKWebView -> IO ())
27+ -> CString
28+ -> StablePtr (IO ()) -- willFinishLaunchingWithOptions
29+ -> StablePtr (IO ()) -- didFinishLaunchingWithOptions
30+ -> StablePtr (IO ()) -- applicationDidBecomeActive
31+ -> StablePtr (IO ()) -- applicationWillResignActive
32+ -> StablePtr (IO ()) -- applicationDidEnterBackground
33+ -> StablePtr (IO ()) -- applicationWillEnterForeground
34+ -> StablePtr (IO ()) -- applicationWillTerminate
35+ -> StablePtr (IO ()) -- applicationSignificantTimeChange
36+ -> Word64 -- whether to run requestAuthorizationWithOptions
37+ -> Word64 -- Ask for Badge authorization
38+ -> Word64 -- Ask for Sound authorization
39+ -> Word64 -- Ask for Alert authorization
40+ -> Word64 -- Ask for CarPlay authorization
41+ -> Word64 -- registerForRemoteNotifications
42+ -> StablePtr (CString -> IO ()) -- didRegisterForRemoteNotificationsWithDeviceToken
43+ -> StablePtr (CString -> IO ()) -- didFailToRegisterForRemoteNotificationsWithError
44+ -> IO ()
45+
46+data AppDelegateConfig = AppDelegateConfig
47+ { _appDelegateConfig_willFinishLaunchingWithOptions :: IO ()
48+ , _appDelegateConfig_didFinishLaunchingWithOptions :: IO ()
49+ , _appDelegateConfig_applicationDidBecomeActive :: IO ()
50+ , _appDelegateConfig_applicationWillResignActive :: IO ()
51+ , _appDelegateConfig_applicationDidEnterBackground :: IO ()
52+ , _appDelegateConfig_applicationWillEnterForeground :: IO ()
53+ , _appDelegateConfig_applicationWillTerminate :: IO ()
54+ , _appDelegateConfig_applicationSignificantTimeChange :: IO ()
55+ , _appDelegateConfig_appDelegateNotificationConfig :: AppDelegateNotificationConfig
56+ }
57+
58+instance Default AppDelegateConfig where
59+ def = AppDelegateConfig
60+ { _appDelegateConfig_willFinishLaunchingWithOptions = return ()
61+ , _appDelegateConfig_didFinishLaunchingWithOptions = return ()
62+ , _appDelegateConfig_applicationDidBecomeActive = return ()
63+ , _appDelegateConfig_applicationWillResignActive = return ()
64+ , _appDelegateConfig_applicationDidEnterBackground = return ()
65+ , _appDelegateConfig_applicationWillEnterForeground = return ()
66+ , _appDelegateConfig_applicationWillTerminate = return ()
67+ , _appDelegateConfig_applicationSignificantTimeChange = return ()
68+ , _appDelegateConfig_appDelegateNotificationConfig = def
69+ }
70+
71+data AuthorizationOption = AuthorizationOption_Badge
72+ | AuthorizationOption_Sound
73+ | AuthorizationOption_Alert
74+ | AuthorizationOption_CarPlay
75+ deriving (Show, Read, Eq, Ord)
76+
77+data AppDelegateNotificationConfig = AppDelegateNotificationConfig
78+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions :: Maybe (Set AuthorizationOption)
79+ , _appDelegateNotificationConfig_registerForRemoteNotifications :: Bool
80+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken :: CString -> IO ()
81+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError :: CString -> IO ()
82+ }
83+
84+instance Default AppDelegateNotificationConfig where
85+ def = AppDelegateNotificationConfig
86+ { _appDelegateNotificationConfig_requestAuthorizationWithOptions = Nothing
87+ , _appDelegateNotificationConfig_registerForRemoteNotifications = False
88+ , _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken = \_ -> return ()
89+ , _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError = \_ -> return ()
90+ }
91+
1892
1993-- | Run JSaddle in a WKWebView
20−run :: JSM () -> IO ()
21−run f = do
22− handler <- newStablePtr (jsaddleMain f)
23− progName <- getProgName
24− withCString progName $ runInWKWebView handler
94+run :: AppDelegateConfig -> JSM () -> IO ()
95+run = run' Nothing
2596
2697-- | Run JSaddle in a WKWebView first loading the specified file
2798-- from the mainBundle (relative to the resourcePath).
2899runFile :: ByteString -- ^ The file to navigate to.
29100 -> ByteString -- ^ The path to allow read access to.
30− -> JSM () -> IO ()
31−runFile url allowing f = do
32− handler <- newStablePtr (jsaddleMainFile url allowing f)
101+ -> AppDelegateConfig
102+ -> JSM ()
103+ -> IO ()
104+runFile url allowing = run' $ Just (url, allowing)
105+
106+run' :: Maybe (ByteString, ByteString)
107+ -> AppDelegateConfig
108+ -> JSM ()
109+ -> IO ()
110+run' mUrl cfg f = do
111+ handler <- case mUrl of
112+ Just (url, allowing) -> newStablePtr (jsaddleMainFile url allowing f)
113+ Nothing -> newStablePtr (jsaddleMain f)
33114 progName <- getProgName
34− withCString progName $ runInWKWebView handler
115+
116+ -- AppDelegate callbacks
117+ willFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_willFinishLaunchingWithOptions cfg
118+ didFinishLaunchingWithOptions <- newStablePtr $ _appDelegateConfig_didFinishLaunchingWithOptions cfg
119+ applicationDidBecomeActive <- newStablePtr $ _appDelegateConfig_applicationDidBecomeActive cfg
120+ applicationWillResignActive <- newStablePtr $ _appDelegateConfig_applicationWillResignActive cfg
121+ applicationDidEnterBackground <- newStablePtr $ _appDelegateConfig_applicationDidEnterBackground cfg
122+ applicationWillEnterForeground <- newStablePtr $ _appDelegateConfig_applicationWillEnterForeground cfg
123+ applicationWillTerminate <- newStablePtr $ _appDelegateConfig_applicationWillTerminate cfg
124+ applicationSignificantTimeChange <- newStablePtr $ _appDelegateConfig_applicationSignificantTimeChange cfg
125+
126+ -- AppDelegate notification configuration
127+ let ncfg = _appDelegateConfig_appDelegateNotificationConfig cfg
128+ (requestAuthorizationWithOptions, authorizationOptions) =
129+ case _appDelegateNotificationConfig_requestAuthorizationWithOptions ncfg of
130+ Nothing -> (False, Set.empty)
131+ Just opts -> (True, opts)
132+ registerForRemoteNotifications = _appDelegateNotificationConfig_registerForRemoteNotifications ncfg
133+ didRegisterForRemoteNotificationsWithDeviceToken <- newStablePtr $ _appDelegateNotificationConfig_didRegisterForRemoteNotificationsWithDeviceToken ncfg
134+ didFailToRegisterForRemoteNotificationsWithError <- newStablePtr $ _appDelegateNotificationConfig_didFailToRegisterForRemoteNotificationsWithError ncfg
135+ withCString progName $ \pn -> runInWKWebView
136+ handler
137+ pn
138+ willFinishLaunchingWithOptions
139+ didFinishLaunchingWithOptions
140+ applicationDidBecomeActive
141+ applicationWillResignActive
142+ applicationDidEnterBackground
143+ applicationWillEnterForeground
144+ applicationWillTerminate
145+ applicationSignificantTimeChange
146+ (fromBool requestAuthorizationWithOptions)
147+ (fromBool $ Set.member AuthorizationOption_Badge authorizationOptions)
148+ (fromBool $ Set.member AuthorizationOption_Sound authorizationOptions)
149+ (fromBool $ Set.member AuthorizationOption_Alert authorizationOptions)
150+ (fromBool $ Set.member AuthorizationOption_CarPlay authorizationOptions)
151+ (fromBool registerForRemoteNotifications)
152+ didRegisterForRemoteNotificationsWithDeviceToken
153+ didFailToRegisterForRemoteNotificationsWithError
jsaddle-wkwebview/src/Language/Javascript/JSaddle/WKWebView/Internal.hs+16−3
@@ -30,7 +30,9 @@ newtype JSaddleHandler = JSaddleHandler (Ptr JSaddleHandler)
3030foreign export ccall jsaddleStart :: StablePtr (IO ()) -> IO ()
3131foreign export ccall jsaddleResult :: StablePtr (Results -> IO ()) -> CString -> IO ()
3232foreign export ccall jsaddleSyncResult :: StablePtr (Results -> IO Batch) -> JSaddleHandler -> CString -> IO ()
33−foreign export ccall withWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
33+foreign export ccall callWithWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
34+foreign export ccall callWithCString :: CString -> StablePtr (CString -> IO ()) -> IO ()
35+foreign export ccall callIO :: StablePtr (IO ()) -> IO ()
3436foreign import ccall addJSaddleHandler :: WKWebView -> StablePtr (IO ()) -> StablePtr (Results -> IO ()) -> StablePtr (Results -> IO Batch) -> IO ()
3537foreign import ccall loadHTMLString :: WKWebView -> CString -> IO ()
3638foreign import ccall loadBundleFile :: WKWebView -> CString -> CString -> IO ()
@@ -95,11 +97,21 @@ jsaddleSyncResult ptrHandler jsaddleHandler s = do
9597 useAsCString (toStrict $ encode batch) $
9698 completeSync jsaddleHandler
9799
98−withWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
99−withWebView webView ptrF = do
100+callWithWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
101+callWithWebView webView ptrF = do
100102 f <- deRefStablePtr ptrF
101103 f webView
102104
105+callWithCString :: CString -> StablePtr (CString -> IO ()) -> IO ()
106+callWithCString c fptr = do
107+ f <- deRefStablePtr fptr
108+ f c
109+
110+callIO :: StablePtr (IO ()) -> IO ()
111+callIO ptr = do
112+ f <- deRefStablePtr ptr
113+ f
114+
103115jsaddleJs :: ByteString
104116jsaddleJs = ghcjsHelpers <> "\
105117 \runJSaddleBatch = (function() {\n\
@@ -128,3 +140,4 @@ mainBundleResourcePath = do
128140 if bs == nullPtr
129141 then return Nothing
130142 else Just <$> packCString bs
143+