I am trying to create a dynamic framework project, I can use to inject code and for reverse engineering purposes.
I've been successfully able to inject code using Objective C file "(.m)" file.
#import <Foundation/Foundation.h>
#import "CodeInjection-Swift.h" // This line gives error.
#interface CodeInjection: NSObject
#end
#implementation CodeInjection
static void __attribute__((constructor)) initialize(void){
NSLog(#"==== Code Injection in Action lolz====");
[[CodeInjectionSwift shared] performTask];
}
#end
I also have a file called "CodeInjectionSwift.swift"
import Foundation
import NetworkInterceptor
#objc class CodeInjectionSwift: NSObject {
#objc public static let shared = CodeInjectionSwift()
override private init(){}
#objc func performTask(){
let requestSniffers: [RequestSniffer] = [
RequestSniffer(requestEvaluator: AnyHttpRequestEvaluator(), handlers: [
SniffableRequestHandlerRegistrable.console(logginMode: .nslog).requestHandler()
])
]
let requestRedirectors: [RequestRedirector] = [
RequestRedirector(requestEvaluator: DomainHttpRequestEvaluator(domain: "www.antennahouse.com"), redirectableRequestHandler: AlternateUrlRequestRedirector(url: URL(string: "https://www.rhodeshouse.ox.ac.uk/media/1002/sample-pdf-file.pdf")!))
]
let networkConfig = NetworkInterceptorConfig(requestSniffers: requestSniffers,
requestRedirectors: requestRedirectors)
NetworkInterceptor.shared.setup(config: networkConfig)
NetworkInterceptor.shared.startRecording()
}
}
If I get rid of the #import "CodeInjection-Swift.h" and the line [[CodeInjectionSwift shared] performTask];
The NSLog prints and am able to build successfully. I was told that I have to import -Swift.h file to use swift classes in CondeInjection-swift.h
Error message is
"-Swift.h not found"
My goal is to build the framework, and be able to utilize "CodeInjectionSwift" functionality that uses import NetworkInterceptor
Related
I have React Native app and I need to implement native modules on IOS with RCT_EXTERN_METHOD macros.
My steps:
Created Settings.swift file in XCode.
Created Bridging - Header.
Created Settings.m file in XCode.
Declared Class component and inside variable and function in Settings.swift file in Xcode.
Registered functions in Settings.m file with RCT_EXTERN_METHOD macros in XCode.
Imported Native Modules and used it in React Native project.
I need to use variables from my swift file like state in my React Native project and manage it with declared function from Swift file. When i call the function it works, but i can not get variables from Native Modules like NativeModules.Settings.getSwitchGeneralTagLog
i get undefined. Can you tell me please how can i get variable from Native Module? And is it good way to use it for state? Which the best way to manage state in Swift?
Settings.swift:
import Foundation
#objc(Settings)
class Settings: NSObject {
private var generalTagLog = false
#objc
func getSwitchGeneralTagLog() -> Bool {
return generalTagLog
}
#objc
func switchGeneralTagLog() -> Bool {
return generalTagLog ? false : true
}
#objc
static func requiresMainQueueSetup() -> Bool {
return true
}
}
Settings.m:
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#interface RCT_EXTERN_MODULE(Settings, NSObject)
RCT_EXTERN_METHOD(switchGeneralTagLog)
#end
I am going to focus on one function and you can extend it based on that
Settings.m
RCT_EXTERN_METHOD(getSwitchGeneralTagLog:(RCTPromiseResolveBlock)promise rejector: (RCTPromiseRejectBlock)reject)
In the below scenario, we are not processing any exception
Settings.swift
#objc func getSwitchGeneralTagLog(_ promise: RCTPromiseResolveBlock, rejector reject: RCTPromiseRejectBlock) {
var isSwitch = false
// figure out what need to be done for the flag
promise(isSwitch)
}
in your RN Accept you can extract the result from promise and use it.
Say I have a class called ExampleClass.
Say I then write code like so:
#objc(ExampleClass)
class ExampleClass: NSObject {
#objc class func exampleFunc() -> Void {
}
}
With an Objective-C file header like so:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(ExampleClass, NSObject)
RCT_EXTERN_METHOD(exampleFunc)
#end
Which I then consume in my React Native app like so:
console.log('exampleClass', React.NativeModules.ExampleClass);
console.log('exampleFunc', React.NativeModules.ExampleClass.exampleFunc)
The first console log results in {exampleFunc: f}
The second results in undefined,
Calling the function: React.NativeModules.ExampleClass.exampleFunc() results in an app crash with:
Exception 'exampleFunc is not a recognized Objective-C method.' was thrown while invoking setupLogger on target ExampleClass with params (
While changing only the Swift so that it reads:
#objc(ExampleClass)
class ExampleClass: NSObject {
#obj func exampleFunc() -> Void {
}
}
results in calling the function (which, yes) does nothing at present.
How can I expose class level variables? I am trying to write functional Swift, and I am using class methods to simulate structs.
I believe the problem is that RCT_EXPORT_METHOD() only works on instance methods, not class methods, according to my own similar problem and some discussion here: https://github.com/facebook/react-native/issues/2311
My use case is trying to bridge a getInstance() method for a Swift singleton class. This is problematic because when you reference NativeModules.ExampleClass from javascript, which has been exported with RCT_EXTERN_MODULE(), RN calls init() on its own, which you don't want for a singleton (init() reference: https://samwize.com/2017/02/09/calling-a-view-controller-function-from-react-native/)
The best way I've found to accomplish this is pretty ugly. I have a dummy wrapper class that does nothing except call methods on the singleton, and this is the class I export to Objective C (and therefore to React Native). It's basically like this:
#objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
#objc(pseudoSingletonSomeMethod)
public func pseudoSingletonSomeMethod() {
let singleton = ActualClass.getInstance()
singleton.someMethod()
}
}
and then in the .m bridge file:
#interface RCT_EXTERN_MODULE(StupidWrapperClass, NSObject)
RCT_EXTERN_METHOD(pseudoSingletonSomeMethod)
#end
You could do something like this for a class method, too:
#objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
#objc(pseudoClassMethod)
public func pseudoClassMethod() {
ActualClass.theRealClassMethod()
}
}
I know I'm kinda late to the party but I recently faced the same problem and I fixed it using a different approach. Adding to the answer given above by #thejoelpatrol, a different approach would be to store the object's reference created by react native in some static variable that would be accessible by you. Then we can use the variable to access the object created by react-native anytime.
Whenever React Native tries to instantiate the class, it would come to the init. inside the init, we can save the reference to the object created by RN.
#objc public class MyClass {
#objc public static var shared: MyClass?
init() {
MyClass.shared = self
}
}
The .m bridge file is as follows:
#interface RCT_EXTERN_MODULE(MyClass)
RCT_EXTERN_METHOD(myClassMethod)
#end
I am creating a swift framework. In that one class is like this as shown below.
import Foundation
#objc public class classA: NSObject {
public override init (){
super.init();
}
/**
Singleton intance is returned.
*/
public class var sharedInstance: classA {
struct Static {
static let instance = popeye();
}
return Static.instance
}
}
Now when i add this framework into a Objective c project and try to access "sharedInstance" i get this error.
Property 'sharedInstance' not found on object of type ClassA.
Fix it Replace 'sharedInstance' with 'sharedInstance'
But even if i try use Fix it, this issue isnt solved.
NOTE: This issue doesn't happen when i integrate this framework with a swift project!!!
I AM STUCK.. :(
I tried to reproduce your problem. At first the syntax highlighter in Xcode flagged the same error in Objective-C that you mentioned, but the code actually was built and ran fine.
However, there is a cleaner way of doing this. In your code you are using a computed type property, which is evaluated every time you access it! You work around this by introducing the struct Static, where you essentially do what could be done in classA itself, like this:
/**
Singleton intance is returned.
*/
public static var sharedInstance: classA = popeye()
Here we used a stored type property, which is a recommended way to implement singletons, see here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html
And here is some documentation on different kinds of properties:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
Finally i was able to fix this with a minor change !! :)
Swift framework code
#objc class SingletonTest: NSObject {
// swiftSharedInstance is not accessible from ObjC
class var swiftSharedInstance: SingletonTest {
struct Singleton {
static let instance = SingletonTest()
}
return Singleton.instance
}
// the sharedInstance class method can be reached from ObjC
class func sharedInstance() -> SingletonTest {
return SingletonTest.swiftSharedInstance
}
// Some testing
func testTheSingleton() -> String {
return "Hello World"
}
}
Objective C parent project code
SingletonTest *aTest = [SingletonTest sharedInstance];
NSLog(#"Singleton says: %#", [aTest testTheSingleton]);
I'm trying to bridge my React-Native 0.33 code to a super simple Swift method, following this guide but all I'm getting is show:(NSString *)name is not a recognized Objective-C method.
Here's my code:
SwitchManager.swift
import Foundation
#objc(SwitchManager)
class SwitchManager: NSObject {
#objc func show(name: String) -> Void {
NSLog("%#", name);
}
}
SwitchManagerBridge.h
#import "RCTBridgeModule.h"
#interface RCT_EXTERN_MODULE(SwitchManager, NSObject)
RCT_EXTERN_METHOD(show:(NSString *)name)
#end
SwitchManager-Bridging-Header.h
#import "RCTBridgeModule.h"
Then on my index.ios.js file I'm importing SwitchManager with import { SwitchManager } from 'NativeModules'; and calling SwitchManager.show('One');. This is where the error happened.
Not sure what's wrong.
This is a part of Swift 3's changes and can be solved by adding an underscore:
import Foundation
#objc(SwitchManager)
class SwitchManager: NSObject {
#objc func show(_ name: String) {
NSLog("%#", name);
}
}
See Swift 3's 0046 Proposal: Establish consistent label behavior across all parameters including first labels that is called out in the Swift.org migration guide under "Consistent first argument labels".
Basically, how Objective-C sees Swift methods has changed with Swift 3.
EDIT: This is still the case in Swift 4, see docs here under Omitting Argument Labels.
this worked for me in xcode 8.0 and swift 3
#objc func openPresentedViewController(_ name: String,name1: String,name2: String){
}
add _ to non labelled members
RCT_EXTERN_METHOD(methodName:(NSString *)name name1:(NSString *)name1 name2:(NSString *)name2)
as you can see in the objective c method name is nonlabeled parameter add _ to it in the swift method
I was fighting with this issue all day. Resolved by setting the Swift Compiler to use Legacy versions (XCode 8 is prefers Swift 3), so in:
Build Settings > Scroll down to 'Use Legacy Swift Language Version' set as Yes.
I had the same error because I had forgotten to put the decorator #objc before the function declaration
I've got a class which is implementing the UIPopOverControllerDelegate:
#if ios_atleast_32
#interface MyClass : UIViewController <UIPopoverDelegate>
#elsif
#interface MyClass : UIViewController
#endif
Is it possible to make determine at runtime if the class is available and therefore should be used as delegate? The same for imports:
#if ios_4_available
#import "MyClassWhichIsUsingIos4Stuff.h"
#endif
You're building against the latest SDK so you can always #import new stuff and don't need any preprocessor macros there. The same is true for the protocol.
Just make sure that before using classes that are not available on all your supported OS versions you check whether that class exists or your app will crash:
Class someNewClass = NSClassFromString(#"SomeNewClass");
if (someNewClass) {
...
}
else {
...
}
In newer versions of the SDK (don't ask me what exactly is the requirement) you can also do something like this:
if ([SomeNewClass class]) {
...
}
else {
...
}
You can simply implement the protocol regardless of which iOS version will be used at runtime, and it will work fine.
as the two above mentioned, it's no problem to import classes - but UIKit has to be weakly linked... that was the missing point in my case!