This is the first time I am trying objc_util so not sure if I am doing something wrong. I am trying to access my HomeKit setup and am starting with the following
from objc_util import *
HMHomeManager = ObjCClass('HMHomeManager')
homemanager = HMHomeManager.alloc().init()
This is based on the objective c call:
self.homeManager = [[HMHomeManager alloc] init];
My code crashes Pythonista but removing init() does not. I am sure someone will say "then just remove it" but it appears in looking at other objc_util examples that it is expected to be called. Running without init does let me get the primary home but no rooms - the big "but" is I have not coded the delegate methods which appears to be useful.
Anyhow at this point was wondering if anyone has done anything with HomeKit that they could share. Also wondering about the init() issue.
I suspect your issue is that the delegate and maybe the manager gets destroyed at the end of main(). retain, or return them and retain them in the callers scope.
from __future__ import absolute_import, division, print_function from objc_util import * from pythonista_startup.enable_faulthandler import run load_framework('HomeKit') def homeManagerDidUpdateHomes_(self,sel,manager): print(ObjCInstance(self)) print('homeManagerDidUpdateHomes') methods = [homeManagerDidUpdateHomes_] protocols = ['HMHomeManagerDelegate'] MyHMHomeManagerDelegate = create_objc_class('MyHMHomeManagerDelegate',NSObject,methods=methods,protocols=protocols) def main(): print('Start of script') # run enable faulthandler run() #every alloc must have an init, or initWith... #, or can use .new() instead of .alloc().init() myHMHomeManagerDelegate = MyHMHomeManagerDelegate.alloc().init() HMHomeManager = ObjCClass('HMHomeManager') homemanager = HMHomeManager.alloc().init() homemanager.setDelegate(myHMHomeManagerDelegate) # homemanager and delegate must be retained, or returned, # otherwise python object gets destroyed return homemanager,myHMHomeManagerDelegate #alternatively #retain_global(myHMHomeManagerDelegate) #retain_global(homemanager) print('End of script') if __name__ == '__main__': homemanager,myHMHomeManagerDelegate = main()
i dont have anything to test with, but this doesnt crash, and you can call the delegate manually...
edit: also, i think the proper delegate method is
which takes homes, and manager args.
edit: nope.. the original was right
you were missing the underscore. You have to replace colons with underscore for methods that take arguments. This did get called automatically
Thanks for looking into this and the reply. I pasted your code into a new script file and unfortunately it is crashing pythonista at the alloc init again. If I take off the init it crashes when setting the delegate as before. I am using a different iOS device than yesterday but I appear to be having the same issue. I am running iOS 11.2.5 on the device I am trying it on now if that matters.
Which init is crashing? The delegate or the manager?
You can't skip init, you don't really have an objc object until you run init. Alternatively, try new() instead of alloc ().init().
Did you get a pop-up allowing homekit access? Check settings app. I think homekit requires an entitlement but don't know whether that was always enforced, or if pythonista has that entitlement. I'm on a os9.4 device.
The delegate is created first and the init on it causes a crash. If I comment that line or remove the init then the HMHomeManager causes the crash with the init. Also tried new() with the same result.
I did not get a popup asking for HomeKit access. I just checked in Xcode and HomeKit is a capability that needs turned on for the app (pythonista in this case as you mention). Ultimately it has to be set on the app id (Xcode will do this or can be done in the developer portal for the app id).
Will send a support email asking about this.
I'm not sure which version of iOS started enforcing the entitlement. Again, it works for me. Creating the delegate should not require the entitlement, since it does jnot do anything. Try creating just the delegate, and using alloc().init(). Then try again without specifying the protocol. If that still crashes, try without the method.
Can you also try one of the objc examples that use a custom delegate class? Just to ensure objc_util is really working...
Oh, also use the debug=True flag in your create_objc_class. Your code could fail because the class name might not be unique. Not sure.
Also, I'm on the beta, which might have different entitlements... @omz?
I tried a different sample app that uses alloc init and delegates and it works. Heard back from Ole and Pythonista is not a HomeKit app and it does appear it will become one. I am guessing that is why it is crashing. Thanks for the help.
My use case is to provide a different UI and organization for HomeKit triggers based on how I am using it. I know how to develop apps in Swift and could go that route but I believe the free developer account apps are only signed for 7 days. This will not be a frequently used app and I could go that route (having to deploy it from Xcode each time I need to run it after 7 days from last run). Pythonista would have filled the need perfectly if it was HomeKit capable.
i would have expected entitlement problems to show up in faulthandler as such. also, i cannot believe you need an entitlement to create a custom delegate class.
Id like to suggest a custom settrace() so we can find exactly where the crash occurs (it probably is in the objc_util call somewhere, but it would be interesting to see exactly which line. I think you said your were getting segfault, which sounds like a different problem.
@JonB, do you think there is still a solution to be found, even if Pythonista app is not HomeKit-enabled?
It is not obvious that the entitlement is the problem -- also, I am not sure it is enforced on app, versus just in Xcode, since the example works for me. Maybe it is enforced in later ios versions, or not enforced on the testflight version... do you get the same crash mikael?
@JonB, I am on 11.2.6 and get a crash with ”Fatal Python error: Aborted” at HomeManager init, delegate init is fine.