Can XCode check for the code compatibility against a specific OS X version? or an external tool?
I have a project that's using a function exists at 10.9 and newer, though I set xcode deployment target to 10.7, it builds without errors but when trying to run the application on 10.8, it doesn't work!!
how can I get functions minimum OS version required?
Xcode does not provide a tool to check whether a method is available for the deployment target. But if you know that some method is only available from a specific version you can check whether the method is available:
if ([self respondsToSelector:#selector(newMethodNotAlwaysAvailable:withParameters:)]) {
[self newMethodNotAlwaysAvailable:#"1" withParameters:YES];
}
else {
// Call some other method to just don't do anything.
}
You can also do ut for classes:
if ([SomeNewClass Class] ) {
// Class is available and you can use it
}
Related
I need to get the Versions of all the installed applications programmatically for non-jailbroken iOS devices.
Is it Possible to achieve this?
That's possible, please try the below code.
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:#selector(defaultWorkspace)];
for (LSApplicationProxy *apps in [workspace performSelector:#selector(allApplications)])
{
NSString *localizedName = apps.localizedName;
if([apps.applicationType isEqualToString:#"User"])
{
NSLog(#"\nlocalizedName: %#",localizedName);
NSLog(#"minimumSystemVersion: %#",apps.minimumSystemVersion);
NSLog(#"fileSharingEnabled: %d",apps.fileSharingEnabled);
NSLog(#"sdkVersion: %#",apps.sdkVersion);
NSLog(#"teamID: %#",apps.teamID);
}
}
For this you need to place 4 classes in your app:
LSApplicationWorkspace, LSResourceProxy, LSBundleProxy, LSApplicationProxy.
In iOS8 and before, we can use canOpenUrl to get installed applications which registered schemes. In iOS9, you must add a "white list" into your info.plist file. Only the application in the "white list" can be checked. And the limit count of the "white list" is 50. So you'd better jailbreak your device.
See more information: How to check particular app is already installed on iphone device or not?
Another one: http://useyourloaf.com/blog/querying-url-schemes-with-canopenurl.html
Here is the situation:
I have a client's java project open in eclipse. It uses a JNI library created by an Xcode Objective C project. Is there any good way for me to debug the C code from eclipse when I execute the Java code? Obviously eclipse's default debugger cannot step into the jni library file and we lose the thread (thread meaning investigative thread here, not programming thread).
Any advice or input is appreciated as the code base is large enough that following the client's code will be radically faster than other options.
Thanks.
EDIT:
It should be noted that the reason that the jni library is written in Objective-C is because it is integrating with Mac OSX. It is using the Cocoa framework to integrate with the Apple speech api.
I am not sure that I have fully understood your setup and if you require this to be done from eclipse or not. Anyhow I was interested in doing a little test program using JNI and a Cocoa library doing nothing just to try the debugging of the obj-c/c code.
I succeeded to do this setup and also to debug the code. I use IntelliJ for Java and Xcode for the objc/c part but doing the java part in eclipse is a no-brainer.
So you should be able to set up exactly my project structure and get going with the debugging. And from there you should be able to apply this knowledge to your own more complex code.
This is how I started off:
Create a new project in Xcode by choosing Cocoa Library.
Name the project libnative and make it of Type Dynamic.
Choose a place for your new project. I use ~/Development/ and skip the Create local git... part.
This will create a new project called lib native.xcodeproj in your selected folder. Two files have been automatically created: libnative.h and libnative.m.
First you must change the Project Settings.
Executable Extension in the Packaging section must be changed from dynlib to jnilib.
Framework Search Paths in the Search Paths section must be updated to point to the JNI framework: /System/Library/Frameworks/JavaVM.framework/Frameworks/JavaNativeFoundation.framework/
Now its time to add some code. Be aware that with this setup you will have to use <JavaVM/jni.h>. Update the libnative.m to look like the following code:
//
// libnative.m
// libnative
//
// Created by maba on 2012-10-09.
// Copyright (c) 2012 maba. All rights reserved.
//
#import "libnative.h"
#include <JavaVM/jni.h>
#implementation libnative
#end
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VEC_LEN
#define VEC_LEN(v) (sizeof(v)/sizeof(v[0]))
#endif/*VEC_LEN*/
static JavaVM *javaVM;
static void print();
static JNINativeMethod Main_methods[] =
{
{ "print", "()V", (void*)print },
};
static struct {
const char *class_name;
JNINativeMethod *methods;
int num_methods;
} native_methods[] = {
{ "com/stackoverflow/Main", Main_methods, VEC_LEN(Main_methods) },
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env = 0;
jclass cls = 0;
jint rs = 0;
if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)) {
return JNI_ERR;
}
javaVM = jvm;
for (unsigned int i = 0; i < VEC_LEN(native_methods); i++) {
cls = (*env)->FindClass(env, native_methods[i].class_name);
if (cls == NULL) {
return JNI_ERR;
}
rs = (*env)->RegisterNatives(env, cls, native_methods[i].methods, native_methods[i].num_methods);
assert(rs == JNI_OK);
}
return JNI_VERSION_1_4;
}
static void print(JNIEnv *env, jclass cls) {
printf("Hello from C");
}
#ifdef __cplusplus
}
#endif
Build the code by pressing ⌘+B.
And now it is time to create the Java code. I simply created a class called Main in package com.stackoverflow.
com.stackoverflow.Main.java
package com.stackoverflow;
/**
* #author maba, 2012-10-09
*/
public class Main {
static native void print();
static {
System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("native");
}
public static void main(String[] args) {
System.out.println("Loading native");
Main.print();
}
}
Set a breakpoint on the line before Main.print();. Start the debugger with the following JVM option:
-Djava.library.path="/Users/maba/Library/Developer/Xcode/DerivedData/libnative-cquleqohzyhghnercyqdwpnznjdf/Build/Products/Debug/"
This line is a little long and also user specific. You will have to look for yourself what the directory names are but they will be more or less the same as mine except for the generated libnative-cquleqohzyhghnercyqdwpnznjdf path.
The program should be running and waiting at the breakpoint. Time to attach the Xcode debugger to the running application.
Choose menu Product -> Attach to Process > and point to the running java process in the System part of the drop down. If there are several java processes then it is most likely the one with the highest PID but not always. You'll have to try.
Create a breakpoint in the c code on the line printf("Hello from C");.
Go back to the Java IDE and continue the execution from where it was halting.
Go back to Xcode and see that it is waiting at the breakpoint!
As I stated earlier this is a very simple approach to the obj-c/JNI and your project is probably quite large but with this small test project you can at least see how it works and then continue to your own project setup.
You might be able to attach with gdb (or lldb) from the Terminal. If the launching of the process w/the native code is the result of a fork()/exec() -- i.e. if you can't type gdb /some/command/line -- then you can likely use the --waitfor option (see the man page) to wait for the launch of the inferior.
Loading symbols will be tricky.
This is a Mac OS X project using the cocoa framework. Does that affect
this?
It shouldn't. If anything, it'll make it easier in that, hopefully, the symbol files are of a usable format. The key is typically finding the right spot to break at the boundary between java and native code.
Is the native code in a dylib that is loaded into the JVM or do you have a custom executable that fires up the JVM internally?
In any case, you need to attach the native debugger to whatever process is running that native code. Probably after you've set up the java based debugging session appropriately.
In the past when doing JNI I have built a test-harness to facilitate the development of the native part of the application - and JNI code - which is notorious easy to screw up, avoiding the need to debug simultaneously from both sides.
This was written as a native application that invokes the JVM programmatically rather than starting with a Java application and then attempting to attach to JVM.
You can of course, start this and debug it in Xcode - which is an infinitely preferable experience to Eclipse with CDT.
The Java side of this arrangement is usually pretty simple and non-contriverial - basically a method which is called from the native part of the app that then makes one or more calls back into the native portion through JNI.
Here are the steps I follow to debug JNI (C/C++) under Windows, I presume ObjectiveC need the same. For Linux it's very similar (replace ; by :, %XXX% by ${XXX}...).
Create a file named MyDebug.gdbinit
Add these 4 lines into it:
set args -classpath .;xxxx.jar;yyy.jar path.to.your.Main
show args
run
bt
launch gdb and Java: gdb "%JAVA_HOME%\bin\java"
Use the GUI of the Java layer to reproduce the error
If you want to execute step by step your JNI code, gdb allows you to put some breakpoints
I want some code tobe compiled under 10.6 and below but not 10.7 and above.
For example:
#ifdef current version is MAC_OS_X_VERSION_10_6 or below
// do this
elif current version is MAC_OS_X_VERSION_10_7 or above
//do that
#endif
Can someone help me ge proper macros for it? I looked into AvailabilityMacros.h but was not able to figure out proper ifdef.
I have a dynamic library, and it cannot be loaded under 10.7 and above but loads properly under 10.6. This is due to private symbol _CGContextAppendPath. I want to keep it using under 10.6 and below but avoid its use in 10.7 and below. This is because _CGContextAppendPath symbol is not present on 10.7 and above.
I used,
SInt32 version = 0;
Gestalt( gestaltSystemVersion, &version );
bool lionabove = ( version >= 0x1070 );
did not work.
For Objective C, the go-to route would be to check the availability of specific APIs via e.g. [object respondsToSelector:].
For the C library you are using, weak-link to CoreGraphics.framework (so the loading doesn't fail when some functions aren't present) and check for availability of the function in question via &_CGContextAppendPath != NULL.
Details in http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html#//apple_ref/doc/uid/10000163i-CH1-107837 and http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-1114537-BABHHJBC.
Apple introduced a new Availability.h macro file for iOS and Mac OS 10.6 and above (located in <SDK>/usr/include/Availability.h). You can do what you are asking like this:
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
// code to run up through 10.6
#else
// code to run on 10.7 or higher
#endif
Note that this macro is also available (which might be preferable depending on your logic):
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
// code to run on 10.7 or above
#else
// code to run below 10.7
#endif
The documentation for this is here: Conditionally Compiling for Different SDKs, particularly worth looking at if you are mixing iOS and Mac OS X code. I also highly recommend reading the header file mentioned above.
Apparently, my use of Twitter oAuth (token request) doesn't work in iOS 5... how can I keep this code for anything below iOS 5 and use the new Twitter Framework for iOS 5+?
Is it possible to detect iOS versions?
Thanks!
You (almost) never want to query iOS (or even framework) versions. That (usually) means you're solving the wrong problem.
In this case, you really want to know "can I use Twitter.framework?"
Thanks to the magic of weak linking, you can try something like:
if ([TWTweetComposeViewController canSendTweet]) {
// Do something
}
else {
// Use your original code
}
You can also check for lower level framework components, e.g.:
if ([TWRequest class]) {
// Do something
}
else {
// Use your original code
}
(Obviously you will need to link against Twitter.framework and include the requisite headers.)
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
//tweet
}
First and foremost, the other answers are correct-- you should avoid using iOS version number to check if features exist.
HOWEVER: In case you do indeed have a good reason to check iOS version, my all-time favorite answer for checking iOS version number is in this StackOverflow answer. So elegant.
Detect if the Twitter class is in the installed os :
if (NSClassFromString(#"TWTweetComposeViewController")) {
//use Twitter Framework
}
Do not forget to make the Twitter Framework optional in the list of Frameworks.
I'm new to IOS development, sometimes I use a function but ignore its Doc.
So, I may use some functions are only supported on IOS 4 or even IOS 5, but I want to support IOS 3+.
Does it has any way to check if my app support IOS 3+?
I don't want to check line by line, thx.
And BTW, anonymous function like void (^ funcName)(NSString *) is objective-c feature, right? So it is supported on all IOS version, right?
Change your 'Deployment Target' to 3.x to see if any methods you're using aren't supported on that version.
That however is not a substitute for testing on 3.x; so either find a 3.x device or drop support for that version. Also, blocks (the 'anonymous function' you describe) are only available on iOS 4 and above.
If you want to write different sets of code for different version targets, you can use preprocessor directives:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
... 5.x code here ...
#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
... 4.x code here ...
#else
... 3.x code here ...
#endif
Try running your app on a device running 3.x
by anonymous functions do you mean blocks like:
[self performSomeBlock:^(NSString *smth) {
NSLog(#"%#", smth);
}];
or do you mean just c like definitions (its late so i forgot the legit name)
void doSomething(void *(*func)(NSString *)) {
...
}