11

I have an existing Objective-C app and have developed a SwiftUI iOS 14 Widget for it. So far so good. Now I am trying to reload the timeline from my Objective-C app. I understand that there are no Objective-C api for accessing WidgetCenter, so I have implemented the bridging steps outlined in Apple's documentation (at least I think I have since I am totally new to Swift). I cannot seem to be able to get Widget Center nor WidgetCenter.shared.reloadAllTimelines()recognized in my Objective-C app. I have tried many approaches with no success, so I must be doing something wrong. Any help or suggestions would be greatly appreciated.

grwilde
  • 361
  • 3
  • 9

1 Answers1

22

I faced with the same issue. The solution for this was to create a swift file for example: WidgetKitHelper. Create the assigned swift-objc header with that too (bridging header file) if it not generated automatically you can add it by manually (search for it). In the helper object you can get access to widgetkit, and if you do the rest to be able to see the swift code from your objc code, you can use this as a wrapper.

Tips:

import WidgetKit

@available(iOS 14.0, *)
@objcMembers final class WidgetKitHelper: NSObject {

    class func reloadAllWidgets(){

        #if arch(arm64) || arch(i386) || arch(x86_64)
        WidgetCenter.shared.reloadAllTimelines()
        #endif

    }
}

obj-c code:

First import the swift code by adding:

#import "YourProjectName-Swift.h"

Then you can use:

[WidgetKitHelper reloadAllWidgets];
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
Magyar Miklós
  • 4,182
  • 2
  • 24
  • 42
  • This solution works great - although you do need a opening "{" after class func reloadAllWidgets() – grwilde Sep 23 '20 at 22:45
  • 1
    Ok, I don't know if I missed a step somewhere, but I did this, and got a warning in my OBJC file class method reloadAllWidgets not found – user717452 Sep 24 '20 at 03:38
  • @grwilde if this solved your problem mark it as the answer – Magyar Miklós Sep 24 '20 at 07:41
  • @user717452 did you create he missing objc-swift header file? Are you able to see the widgetkithelper class from objc file? – Magyar Miklós Sep 24 '20 at 07:42
  • I have the header file and I did #import Project-Swift.h with no issues. Is it due to the appdelegate and widget file being on different targets? – user717452 Sep 24 '20 at 11:33
  • 1
    @user717452 you should add this widgetkithelper to your app target not to the extension, or may to both. This helper class will be visible if it s added to all the targets where you wanna use – Magyar Miklós Sep 24 '20 at 14:40
  • Right, that's what I'm meaning. The AppDelegate isn't attached to the Widget Extension target, and when I try to, I get error with _main being a duplicate symbol. When I add the Widget file to the app's main target I get errors about WidgetCenter only being on 14.0 or later, due to deployment being 13.0 on the app itself. – user717452 Sep 24 '20 at 15:39
  • Ok, so I created a new Swift file, added it to both targets, imported WidgetKit, added the class to reload WidgetCenter, and then went to the OBJ-C AppDelegate and ran the code there when the app is launched (For testing purposes) and assigned both NSLog in that, and Print in the Swift file. It says the code was ran, but the widget did not update still. – user717452 Sep 24 '20 at 15:58
  • What do you mean by "Create the assigned swift-objc headers with that too"? When I create a .swift file in my Obj-C project it does not create any headers just a .swift file. – Jackson Oct 02 '20 at 03:30
  • @Jackson you need to have a bridging header file which allows you to have access codes from another language. Take a look at this question https://stackoverflow.com/questions/31716413/xcode-not-automatically-creating-bridging-header And I updated my answer with the missing piece – Magyar Miklós Oct 02 '20 at 08:22
  • #incmiko I see thank you. I got to the point where the header was auto created. I had an error error in Xcode however that the header didn’t exist even though Xcode autocompleted the file name and the file existed. Anyway thank you. I’ll try it again shorty. Actually I solved that issue with some preprocessor macros to make sure I wasn't trying to include my AppName-Swift.h file in the case where that .m file was being used in a Apple Watch or widget target. – Jackson Oct 06 '20 at 01:41
  • @incmiko Do you need to add Widget kist as an optionally linked framework? – stoutyhk Oct 19 '20 at 08:39
  • 1
    @stoutyhk yes you can add it as a Do not embed framework as a link to your main project if it s not added – Magyar Miklós Oct 19 '20 at 09:48
  • After adding your new swift file and the bridging header file. Remember to compile the project by :`Command + B`. As AppName-Swift.h is a compiled file so you need to compile it again to make the relation valid. – guozqzzu Nov 21 '20 at 15:11
  • Coming a bit late to the party, but can anyone explain the reason of that `#if arch(arm64) || arch(i386) || arch(x86_64)`? What archs are we excluding here? – il3v Apr 02 '21 at 08:34
  • @il3v armv7 & armv7s because of the older devices. For example on an iPhone5 it will crash which is using armv7s. – Magyar Miklós Apr 03 '21 at 21:45
  • @incmiko but these architectures don’t rub iOS 14, so they wouldn’t even access this function due to the @available(iOS 14.0, *) statement. Or am i missing something? – il3v Apr 04 '21 at 07:53
  • @il3v you are right, but the problem is coming instanty if you not define what archs support that. Xcode not just warns you about that, it's coming with an error message so you cannot even build (Cannot find type 'WidgetCenter' in scope). – Magyar Miklós Apr 10 '21 at 09:55
  • @user717452 Add `@objc` to the func or class will fix "method not found" issues. – denkeni Aug 03 '21 at 06:17