Here's my code ----
//Cpp/Objective-C Wrapper function
iSketchnoteController * isknController;
extern "C"
{
void launchiSketchnoteController(SlateTableViewController *viewController)
{
try
{
if (viewController == nil) {
isknController = new
iSketchnoteController([MyManager sharedManager].deviceName);
} else {
isknController = new iSketchnoteController(viewController);
}
} catch (Error &err)
{
NSLog(#"Error");
}
}
My desired effect is to have [MyManager sharedManager] be my "static app state." Meaning, a management system throughout my entire app I can use for things like setting a device name, disconnecting it, reconnect it, etc...
Also, the above is a .mm file.
Anyway - here's how I have it implemented.
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
NS_ASSUME_NONNULL_BEGIN
#class SelectSlateTableViewController;
#protocol MySwiftProtocol;
#interface MyManager : NSObject
+ (instancetype)sharedManager;
#property (nonatomic, assign) NSString *deviceName;
#end
NS_ASSUME_NONNULL_END
and the .m file
#import "MyManager.h"
extern void disconnect();
extern void connectToPeripheral(CBPeripheral* peripheral);
extern void connectToPeripheralByName(NSString* name);
extern void launchiSketchnoteController(SelectSlateTableViewController *viewController);
extern void isConnected();
#implementation MyManager
+ (instancetype)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (instancetype)init
{
self = [super init];
return self;
}
#end
Essentialy, in the first code box [MyManager sharedManager].deviceName is NOT accessible.
Related
I have Qt application, I'm calling UIImagePickerController to get file path for movie the user selected. So I have static functions in Objective-C which call functions from .m file, when user selects movie I can read selected path in another .m function. Question is, how to get this filePath into some Objective-C class where I can call another Qt classes (like Singleton) and pass this result to proper class ?
Objective-C CL_image_call.mm
#include "cl_image_call.h"
#include "cl_image_func.h"
myCLImageClass* CL_image_obj=NULL;
int CL_ImageCCall::CL_objectiveC_Call() {
//Objective C code calling.....
if( CL_image_obj==NULL ) {
//Allocating the new object for the objective C class we created
CL_image_obj=[[myCLImageClass alloc]init];
}
return 1;
}
void CL_ImageCCall::CL_openMedia() {
[CL_image_obj openMedia];
}
CL_image_call.h
#include <QImage>
#include <QString>
#include <QDebug>
#include <stdio.h>
#include "my_singleton.h"
class CL_ImageCCall
{
public:
static int CL_objectiveC_Call();
static void CL_openMedia();
};
CL_image_func.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>
#interface myCLImageClass:NSObject
-(void)openMedia;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
#end
CL_image_func.m
#import "cl_image_func.h"
#interface QIOSViewController : UIViewController
#end
#implementation myCLImageClass
UIImagePickerController *picker=NULL;
UIViewController *viewController=NULL;
NSString *f_path;
-(void)openMedia {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
viewController = (UIViewController *)([keyWindow rootViewController]);
if (!viewController)
return;
if([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary]) {
picker= [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeMovie, nil];
[viewController presentViewController:picker animated:YES completion:NULL];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *docDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDirPath stringByAppendingPathComponent:#"movie.mov"];
NSLog (#"File Path = %#", filePath);
//filePath is what I need to pass to the rest of my app
[viewController dismissViewControllerAnimated:YES completion:nil];
}
So in CL_image_call.h I have my "my_singleton" where I can reach my whole app, but how to get filePath to this class ?
Best Regards
Marek
Here is the code to export media:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *docDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDirPath stringByAppendingPathComponent:#"movie.mov"];
NSLog (#"File Path = %#", filePath);
//filePath is what I need to pass to the rest of my app
NSURL *inputURL = [info objectForKey:UIImagePickerControllerMediaURL];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
// config the session, maybe some option is not what you need, just config by what you need
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset
presetName:AVAssetExportPresetMediumQuality];
session.outputURL = [NSURL fileURLWithPath:filePath];
session.outputFileType = AVFileTypeMPEG4;
session.shouldOptimizeForNetworkUse = YES;
[session exportAsynchronouslyWithCompletionHandler:^(void)
{
// do a completion handler
}];
[viewController dismissViewControllerAnimated:YES completion:nil];
}
Then you can visit the output by the filePath, and use when you need.
I have modified code with your suggestion and it does what it should. I'm settings moviePath inside my Qt classes and then I call Objective-C code with this path
NSString *f_path;
//Your objective c code here....
-(void)openMedia:(NSString*)moviePath {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
f_path=moviePath.copy;
viewController = (UIViewController *)([keyWindow rootViewController]);
if (!viewController)
return;
if([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary]) {
picker= [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeMovie, nil];
[viewController presentViewController:picker animated:YES completion:NULL];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *inputURL = [info objectForKey:UIImagePickerControllerMediaURL];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
// config the session, maybe some option is not what you need, just config by what you need
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset
presetName:AVAssetExportPresetMediumQuality];
session.outputURL = [NSURL fileURLWithPath:f_path];
session.outputFileType = AVFileTypeMPEG4;
session.shouldOptimizeForNetworkUse = YES;
[session exportAsynchronouslyWithCompletionHandler:^(void)
{
// do a completion handler
NSLog (#"export complete = %#", f_path);
}];
[viewController dismissViewControllerAnimated:YES completion:nil];
}
with some trick I can view this movie inside Qt app. One thing that is missing:
I need to know somehow that session has been completed, to refresh file path for MediaPlayer. How can I notify my base class CL_ImageCCall about that. Or actually maybe another Objective-C++ class where I can actually mix Qt and Objective-C ?
Best Regards and thanks for Your help
Marek
i try use call c++ from object c
use B4I
this code but i get error
i already use file.mm
this file Greeting.cpp
#include "Greeting.hpp"
Greeting::Greeting() {
greeting = "Hello C++!";
}
std::string Greeting::greet() {
return greeting;
}
this file Greeting.hpp
#ifndef Greeting_hpp
#define Greeting_hpp
#include <stdio.h>
#include <string>
class Greeting {
std::string greeting;
public:
Greeting();
std::string greet();
};
#endif /* Greeting_hpp */
this file ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (void)showGreeting;
#end
this file ViewController.mm
#import "ViewController.h"
#import "Greeting.hpp"
#interface ViewController ()
{
Greeting greeting;
IBOutlet UIButton *helloButton;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)showGreeting {
NSLog(#"test %#");
}
#end
i try call it
ViewController* ViewController1= [[ViewController alloc] init];
[ ViewController1 showGreeting ];
i get error unknown method
-------------------------------
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_ViewController", referenced from:
objc-class-ref in b4i_main.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
---------------------------------
when i use
ViewController* ViewController1;
[ ViewController1 showGreeting ];
return null
note this example HelloCpp-master
thanks
The following example shows how to call a c++ class from an objc app using a method in AppDelegate. It may be run in Terminal by first saving the source code in a file named 'greet.mm' and then using this command: clang greet.mm -framework Cocoa -o greet && ./greet
//clang greet.mm -framework Cocoa -o greet && ./greet
#import <Cocoa/Cocoa.h>
class Greeting {
public:
void greet();
};
void Greeting::greet() {
NSLog(#"Hello C++!");
}
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
NSWindow *window;
}
- (void) myBtnAction: (id)sender;
- (void) buildMenu;
- (void) buildWnd;
#end
#implementation AppDelegate
- (void) myBtnAction: (id)sender {
Greeting g;
g.greet();
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new];
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit"
action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
}
- (void) buildWnd {
#define _wndW 200
#define _wndH 150
window = [ [ NSWindow alloc ] initWithContentRect:NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskClosable | NSWindowStyleMaskTitled
backing:NSBackingStoreBuffered defer:YES];
[window center];
[window setTitle: #"Test window" ];
[window makeKeyAndOrderFront:nil];
// **** My Button **** //
NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 40, 80, 125, 24 )];
[myBtn setBezelStyle:NSBezelStyleRounded ];
[myBtn setTitle: #"Run CPP Class"];
[myBtn setAction: #selector (myBtnAction:)];
[[window contentView] addSubview: myBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 10, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWnd];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
#end
int main () {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[app setDelegate:appDelegate];
[NSApp run];
return 0;
}
Should run in iOS. Change extension of ViewController from .m to .mm
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
#import "ViewController.h"
class Greeting {
public:
void greet();
};
void Greeting::greet() {
NSLog(#"Hello C++!");
}
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UIButton *LaunchBtn;
#end
#implementation ViewController
- (IBAction)showGreeting:(id)sender {
Greeting g;
g.greet();
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
#end
I've got ViewController that contains tableView and an array of items to be displayed on that table.
In order to change table content, I could initialise the array and calling reloadData method from within ViewController button callback (see buttonTap method below).
However, I also need to change the table contents from external code outside the scope of viewController, but it's inaccessible.
In the minimal example below I'm using external C/C++ based thread that unsuccessfully attempts to access a viewController method but it fails on compilation due to No known class method for selector 'changeArr'
Any idea how to make viewController public ?
viewController.m
#import "ViewController.h"
#interface ViewController() <NSTableViewDelegate, NSTableViewDataSource>
#property (weak) IBOutlet NSTableView *tableView;
#property NSMutableArray<NSString*> * arr;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView reloadData];
}
- (void)viewWillAppear {
[super viewWillAppear];
[self.tableView reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.arr.count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSTableCellView* cellView =(NSTableCellView*)[tableView makeViewWithIdentifier:#"cell1" owner:nil];
cellView.textField.stringValue = self.arr[row];
return cellView;
}
-(void)changeArr {
self.arr = [NSMutableArray arrayWithObjects:#"ccc", #"ddd", nil];
[self.tableView reloadData];
NSLog(#"fwefwe");
}
- (IBAction)buttonTap:(id)sender {
self.arr = [NSMutableArray arrayWithObjects:#"AAAA", #"BBB", nil];
[self.tableView reloadData];
}
main.m
#import <Cocoa/Cocoa.h>
#include <pthread.h>
#import "ViewController.h"
void updateTable() {
sleep(10);
dispatch_sync(dispatch_get_main_queue(), ^{ [ViewController changeArr]; }); // ERROR : No known class method for selector 'changeArr'
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Setup code that might create autoreleased objects goes here.
}
pthread_t threadHandler;
pthread_create(&threadHandler, NULL, &updateTable, NULL);
return NSApplicationMain(argc, argv);
}
changeArr is a private function(-). So you can't call [ViewController changeArr].
If you change changeArr to public fuction(+), it's impossible to access internal array.
So I think the easy way to do this task is using a instance of ViewController by singletone.
...
#implementation ViewController
+ (id) sharedViewController {
static ViewController *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
sharedInstance = [storyboard instantiateViewControllerWithIdentifier:#"MyViewControllerIdentifier"];
});
return sharedInstance ;
}
- (void)viewDidLoad {
[super viewDidLoad];
...
and in updateTable:
dispatch_sync(dispatch_get_main_queue(), ^{ [[ViewController sharedViewController] changeArr]; });
I have implemented admob banners in my app already, and now I would like to implement Intersitial ads. The code is written in Obj-C++. Here is the code I have for the banners:
#import "MyGameBridge.h"
#import "AppController.h"
#import "GameConfig.h"
#include "GADInterstitial.h"
void MyGameBridge::showBanner()
{
AppController* delegate = (AppController*)[UIApplication sharedApplication].delegate;
[delegate openAdmobBannerAds];
}
void MyGameBridge::showAds()
{
AppController* delegate = (AppController*)[UIApplication sharedApplication].delegate;
[delegate initiAdBanner];
}
void MyGameBridge::hideAds()
{
AppController* delegate = (AppController*)[UIApplication sharedApplication].delegate;
[delegate hideBanner];
}
What do I need to code to implement Interstitial ads?
Define this in .h file
GADInterstitial *mInterstitial_;
In .m file,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
mInterstitial_ = [[GADInterstitial alloc] init];
mInterstitial_.adUnitID = ADMOB_FULL_SCREEM_ID;
[mInterstitial_ loadRequest:[GADRequest request]];
}
//Use below function to call admob interstitial
-(void)showAdmobAdsFullScreen
{
[mInterstitial_ presentFromRootViewController:self.viewController];
mInterstitial_ = nil;
mInterstitial_ = [[GADInterstitial alloc] init];
mInterstitial_.adUnitID = ADMOB_FULL_SCREEM_ID;
[mInterstitial_ loadRequest:[GADRequest request]];
}
There is no errors in console, and seems everything work. But the bannerView_ just didn't show.
here is my AdMobObject.h
#import "AdMobObject.h"
#import "RootViewController.h"
#import "GADBannerView.h"
#class RootViewController;
#class GADBannerView;
#interface AdMobObject : UIViewController{
RootViewController * viewController;
GADBannerView * bannerView_;
}
+ (AdMobObject *) shared;
- (void) addAdMob;
- ( void) hideAdMob;
#end
here is my AdMobObject.mm
#import "AdMobObject.h"
#import "AppController.h"
#import "RootViewController.h"
#import "EAGLView.h"
#import "cocos2d.h"
#implementation AdMobObject
static AdMobObject* instance;
+(AdMobObject *) shared{
#synchronized(self){
if( instance == nil ){
instance = [[self alloc] init];
}
}
return instance;
}
- (void) addAdMob{
NSLog(#"----------addAdMob");
bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenHeight = screenRect.size.height;
CGFloat screenWidth = screenRect.size.width;
viewController.view.frame = CGRectMake(0,0,screenWidth,screenHeight);
[bannerView_ setFrame:CGRectMake(0,
screenHeight-bannerView_.bounds.size.height,
//0,
bannerView_.bounds.size.width,
bannerView_.bounds.size.height)];
bannerView_.adUnitID = #"myadmobid";
bannerView_.rootViewController = viewController;
[viewController.view addSubview:bannerView_];
GADRequest *request = [GADRequest request];
// For testing
request.testDevices = [NSArray arrayWithObjects:#"mydeviceid", nil];
[bannerView_ loadRequest:request];
[viewController.view addSubview:bannerView_];
}
- (void) showAdMob{
}
- (void) hideAdMob{
[bannerView_ setHidden:YES];
}
#end
Then i have a class to manage it:
#interface MyGameCenterManager : NSObject
{
}
+(MyGameCenterManager *) shared;
+(void) addAdMob;
+(void) hideAdMob;
#end
here is the class implementation:
#implementation MyGameCenterManager
static MyGameCenterManager *instance;
+(MyGameCenterManager*)shared{
#synchronized(self){
if(instance == nil){
instance = [[self alloc] init];
}
}
return instance;
}
+ (void) addAdMob
{
[[AdMobObject shared] addAdMob];
}
+ (void) hideAdMob{
[[AdMobObject shared] hideAdMob];
}
Finally, I have cpp class:
include "cocos2d.h"
#include "ScriptingCore.h"
namespace ls{
class GameCenterBridge: public cocos2d::CCObject{
public:
static cocos2d::CCScene* scene();
virtual bool init();
CREATE_FUNC(GameCenterBridge);
void addAdMob();
void hideAdMob();
};
}
I called my class:
ls::GameCenterBridge * class = new ls::GameCenterBridge();
class->addAdMob();
I can see the console log:
----------addAdMob
which means it enter into the addAdMob function. And there has no other errors.
But the banner view just didn't show.
the only way I make it show is to add codes into AppController.mm in didFinishLaunchingWithOptions. But I am just wondering why it won't work for my self created class.
When i was implementing AdMob i showed the ad only when it got loaded from the server. You can achieve this by implementing GADBannerViewDelegate, especially interesting methods are
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView;
- (void)adView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(GADRequestError *)error
This way you can be sure that you received the ad.