on ca29b24 help sign in
6 files changed+277−25
since splitsnapshots
unifiedsplit
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+133−9 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+133−9
@@ -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
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+