NativeScript / ios-jsc

NativeScript for iOS using JavaScriptCore
http://docs.nativescript.org/runtimes/ios
Apache License 2.0
299 stars 59 forks source link

Unable to create MFMessageComposeViewController #469

Closed firescript closed 8 years ago

firescript commented 8 years ago

Basically just trying to open the message view and pass in an array of numbers to message. When I follow the documentation in the marshelling section (https://docs.nativescript.org/runtimes/ios/marshalling/Marshalling-Overview.html#objective-c-classes-and-objects) the object MFMessageComposeViewController comes back as null. I managed to get an object that seems right using var controller = MFMessageComposeViewController.alloc(). The view just comes back as a white screen with nothing in it though.

Attached is a hello-world project with the code.

messages.zip

ivanbuhov commented 8 years ago

Hi @firescript, The instantiation of MFMessageComposeViewController returns nil when the app is running on emulator due to the lack of SMS services. The behaviour is the same when the app is written in Objective-C, too. Run the app on device and check if still the result of MFMessageComposeViewController.alloc().init() is null (it works on my device). I suggest explicitly calling the desired initializer:

var controller = MFMessageComposeViewController.alloc().init();

instead of using new and relying on the runtime to guess which is the most suitable initializer.

firescript commented 8 years ago

Thanks @ivanbuhov this works for me as well. Trying to get the compose delegate function to work now, it seems when I press cancel or send the message on the device with no delegate set, the view just remains open. I cant get back to the app.

I'm trying to set the delegate like so:

exports.teamMessage = function(){  
    if(MFMessageComposeViewController.canSendText()){
        var controller = MFMessageComposeViewController.alloc().init();
        if(controller != null){
            controller.recipients = ["9059293160","9058184327"];
            controller.body = "Test";
            controller.subject = "Stoney Creek Smoke";
            controller.messageComposeDelegate = function(){

            }            
            var page = frameModule.topmost().ios.controller;
            page.presentModalViewControllerAnimated(controller, true);            
        }else{
            alert("SMS doesn't run in emulator.");
        }             
    } else {
        alert("You're not able to send SMS messages. Please check device settings.");   
    }
}

However this breaks when I place code inside the function, any idea how i could direct the user back to the previous view, possibly with the navigate method so I can pass a message through?

ivanbuhov commented 8 years ago

Hi @firescript, messageComposeDelegate property must be an instance of an interface which implements MFMessageComposeViewControllerDelegate protocol. Supplying a regular JavaScript function will not do the trick. You have to define an interface and implement MFMessageComposeViewControllerDelegate protocol (more on subclassing in NativeScript for iOS):


//If using TypeScript, you can subclass interfaces and implement protocols with regular TypeScript syntax.
//Here we don't use TypeScript, so we use the extend function, supplied by the NativeScript runtime.
var CustomMessageCompositeViewControllerDelegate = NSObject.extend({
    messageComposeViewControllerDidFinishWithResult: function(controller, result) {
        controller.dismissModalViewControllerAnimated(true);

        if(result == MessageComposeResultCancelled) {
            console.log('Message cancelled');
        }
        else if(result == MessageComposeResultSent) {
            console.log('Message sent');
        }
        else {
            console.log('Message failed');
        }
    }

}, {
    protocols: [MFMessageComposeViewControllerDelegate]
});

Configure your MFMessageComposeViewController instance like this:

if(MFMessageComposeViewController.canSendText()){
        var controller = MFMessageComposeViewController.alloc().init();
        if(controller != null){
            controller.recipients = ["9059293160","9058184327"];
            controller.body = "Test";
            controller.subject = "Stoney Creek Smoke";
            controller.messageComposeDelegate = CustomMessageCompositeViewControllerDelegate.alloc().init();
            var page = frameModule.topmost().ios.controller;
            page.presentModalViewControllerAnimated(controller, true);            
        }
    }
firescript commented 8 years ago

Thanks @ivanbuhov this works great.

firescript commented 8 years ago

Hey @ivanbuhov,

I'm getting crashes when I hit cancel, or send. Weird part is sometimes it works, sometimes it doesn't.

I've ran tns device log to try and figure it out. I see a couple weird things:

You can see the code I'm running here: https://github.com/firescript/nativescript-phone

This part:


Jan 12 13:14:07 Ryans-iPhone MessagesViewService[234] <Warning>: _BSMachError: (os/kern) invalid capability (20)

Jan 12 13:14:09 Ryans-iPhone SpringBoard[58] <Warning>: HW kbd: Failed to set (null) as keyboard focus

Jan 12 13:14:09 Ryans-iPhone SpringBoard[58] <Warning>: HW kbd: Failed to set (null) as keyboard focus

Jan 12 13:14:09 Ryans-iPhone SpringBoard[58] <Warning>: HW kbd: Failed to set (null) as keyboard focus

Jan 12 13:14:09 Ryans-iPhone com.apple.xpc.launchd[1] (UIKitApplication:org.nativescript.teamreps[0x5fd0][344]) <Notice>: Service exited due to signal: Segmentation fault: 11

Jan 12 13:14:09 Ryans-iPhone ReportCrash[345] <Notice>: platform_thread_get_unique_id matched 29185

Jan 12 13:14:09 Ryans-iPhone ReportCrash[345] <Notice>: Formulating report for corpse[344] teamreps

Jan 12 13:14:09 Ryans-iPhone ReportCrash[345] <Warning>: saved type '109_teamreps' report (14 of max 25) as /var/mobile/Library/Logs/CrashReporter/teamreps_2016-01-12-131409_Ryans-iPhone.ips

Jan 12 13:14:09 Ryans-iPhone SpringBoard[58] <Warning>: Application 'UIKitApplication:org.nativescript.teamreps[0x5fd0]' crashed.

Jan 12 13:14:09 Ryans-iPhone UserEventAgent[26] <Warning>: 116302534989: id=org.nativescript.teamreps pid=344, state=0

and

Jan 12 13:04:10 Ryans-iPhone com.apple.xpc.launchd[1] (UIKitApplication:org.nativescript.teamreps[0xdee3][321]) <Notice>: Service exited due to signal: Segmentation fault: 11

Jan 12 13:04:10 Ryans-iPhone assertiond[67] <Warning>: Requesting process (<BKNewProcess: 0x13de19970; com.apple.mobilesms.compose; pid: 234; hostpid: -1>) is suspended and cannot obtain assertions

Jan 12 13:04:10 Ryans-iPhone diagnosticd[84] <Error>: unable to find offset 0x818af9a4 in shared cache for arch 'arm64'

Jan 12 13:04:10 Ryans-iPhone ReportCrash[322] <Notice>: platform_thread_get_unique_id matched 25392

Jan 12 13:04:10 Ryans-iPhone ReportCrash[322] <Notice>: Formulating report for corpse[321] teamreps

Jan 12 13:04:10 Ryans-iPhone ReportCrash[322] <Warning>: saved type '109_teamreps' report (13 of max 25) as /var/mobile/Library/Logs/CrashReporter/teamreps_2016-01-12-130410_Ryans-iPhone.ips

Jan 12 13:04:10 Ryans-iPhone SpringBoard[58] <Warning>: Application 'UIKitApplication:org.nativescript.teamreps[0xdee3]' crashed.

Jan 12 13:04:10 Ryans-iPhone UserEventAgent[26] <Warning>: 101935919422: id=org.nativescript.teamreps pid=321, state=0

Jan 12 13:04:11 Ryans-iPhone backboardd[60] <Warning>: CoreAnimation: timed out fence 2a547

Jan 12 13:04:11 Ryans-iPhone MobileSMS[286] <Warning>: Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UIAlertController: 0x16051de60>)

Any idea why this is happening? Here is the full log. If you search for "teamreps", that is my app.

deviceLog2.txt

ivanbuhov commented 8 years ago

Hi @firescript, I tried to reproduce the issue - without success :(. I guess GC collects some unretained objects (e.g. the CustomMessageCompositeViewControllerDelegate instance which is not retained by the MFMessageComposeViewController because its messageComposeDelegate propert is weak). Bring these changes I made in your codebase and see if the issue is reporduced again. I hope this will work.

firescript commented 8 years ago

Hey @ivanbuhov, no luck. It seems to still be crashing. Looks like a js error in the code you provided? I also had to add a "," after initWithResolveReject.

screen shot 2016-01-13 at 12 21 19 pm
firescript commented 8 years ago

That seems to have been fixed now. I'm getting this message when I cancel:

CONSOLE LOG file:///app/tns_modules/nativescript-phone/index.js:56:20: 0
CONSOLE LOG file:///app/tns_modules/nativescript-phone/index.js:59:24: Message Cancelled.
***** Fatal JavaScript exception - application has been terminated. *****
Native stack trace:
1   0x10008712c NativeScript::FFICallback<NativeScript::ObjCMethodCallback>::ffiClosureCallback(ffi_cif*, void*, void**, void*)
2   0x1005a390c ffi_closure_SYSV_inner
3   0x1005a81b4 .Ldo_closure
4   0x181e3b430 <redacted>
5   0x181d38eb4 <redacted>
6   0x1833eb790 <redacted>
7   0x1833ebb10 <redacted>
8   0x181decefc <redacted>
9   0x181dec990 <redacted>
10  0x181dea690 <redacted>
11  0x181d19680 CFRunLoopRunSpecific
12  0x183228088 GSEventRunModal
13  0x186b90d90 UIApplicationMain
14  0x1005a8044 ffi_call_SYSV
15  0x1005a308c ffi_call_int
16  0x1005a2c10 ffi_call
17  0x10005e838 NativeScript::FFICall::call(JSC::ExecState*)
18  0x10034e504 JSC::LLInt::setUpCall(JSC::ExecState*, JSC::Instruction*, JSC::CodeSpecializationKind, JSC::JSValue, JSC::LLIntCallLinkInfo*)
19  0x100354998 llint_entry
20  0x1003549a8 llint_entry
21  0x1003549a8 llint_entry
22  0x1003549a8 llint_entry
23  0x10034ecf8 vmEntryToJavaScript
24  0x1002fad3c JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*)
25  0x1002df8c4 JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&)
26  0x100420eb4 JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&)
FireScript-Mac:teamreps ryanlebel$ 

then when i send:

CONSOLE LOG file:///app/tns_modules/nativescript-phone/index.js:56:20: 1
CONSOLE LOG file:///app/tns_modules/nativescript-phone/index.js:66:24: Message Sent.
***** Fatal JavaScript exception - application has been terminated. *****
Native stack trace:
1   0x10002f12c NativeScript::FFICallback<NativeScript::ObjCMethodCallback>::ffiClosureCallback(ffi_cif*, void*, void**, void*)
2   0x10054b90c ffi_closure_SYSV_inner
3   0x1005501b4 .Ldo_closure
4   0x181e3b430 <redacted>
5   0x181d38eb4 <redacted>
6   0x1833eb790 <redacted>
7   0x1833ebb10 <redacted>
8   0x181decefc <redacted>
9   0x181dec990 <redacted>
10  0x181dea690 <redacted>
11  0x181d19680 CFRunLoopRunSpecific
12  0x183228088 GSEventRunModal
13  0x186b90d90 UIApplicationMain
14  0x100550044 ffi_call_SYSV
15  0x10054b08c ffi_call_int
16  0x10054ac10 ffi_call
17  0x100006838 NativeScript::FFICall::call(JSC::ExecState*)
18  0x1002f6504 JSC::LLInt::setUpCall(JSC::ExecState*, JSC::Instruction*, JSC::CodeSpecializationKind, JSC::JSValue, JSC::LLIntCallLinkInfo*)
19  0x1002fc998 llint_entry
20  0x1002fc9a8 llint_entry
21  0x1002fc9a8 llint_entry
22  0x1002fc9a8 llint_entry
23  0x1002f6cf8 vmEntryToJavaScript
24  0x1002a2d3c JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*)
25  0x1002878c4 JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&)
26  0x1003c8eb4 JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&)
27  0x10003939c -[TNSRuntime executeModule:]
28  0x100004994 main
29  0x1818ba8b8 <redacted>
JavaScript stack trace:
1   messageComposeViewControllerDidFinishWithResult@file:///app/tns_modules/nativescript-phone/index.js:67:20
2   UIApplicationMain@[native code]
3   start@file:///app/tns_modules/application/application.js:200:26
4   anonymous@file:///app/app.js:14:18
5   __executeModule@:139:31
6   __loadModule@:183:24
JavaScript error:
file:///app/tns_modules/nativescript-phone/index.js:67:20: JS ERROR ReferenceError: Can't find variable: resolve
FireScript-Mac:teamreps ryanlebel$ 
ivanbuhov commented 8 years ago

Hi @firescript, I have missed the comma after initWithResolveReject. Also I changed resolve and reject functions to be called with this in front. Check the updated version and try again.

firescript commented 8 years ago

I think that did the trick! As far as I can tell its working as it should! :facepunch: thanks a ton @ivanbuhov

firescript commented 8 years ago

For those that want the end result: https://www.npmjs.com/package/nativescript-messenger

Put credit in the source @ivanbuhov

ivanbuhov commented 8 years ago

Will be glad to help again. Thanks for the credit, I appriciate it :).