Changing Objective-C SDK settings from the application using it - objective-c

I have a question regarding modifying SDK settings from the application using it.
I have a custom SDK which prints to a log when doing certain things. I want users of this SDK to be able to turn logging on/off. I use NSLog as my logger.
I have tried setting a preprocessor macro for this, as explained numerous times here in stackoverflow by doing something like:
#ifdef SHOWLOG
# define SLog(fmt, ...) NSLog((fmt), ##__VA_ARGS__);
#else
# define SLog(...)
#endif
And then expecting the user to set a compile flag called "-DSHOWLOG"
This does not work since the person who is using the SDK will have a compiled version of the SDK.
What other ways are there are there of changing configurations of SDK from the application that uses it?
Are environment variables a good option?

Maybe I'm misunderstanding the question, so I'll guess and offer this answer in the hope it helps:
Inside your SDK create your settings which you query to control how your SDK behaves. These settings can be stored in a shared/singleton object, behind a functional (i.e. C functions) API, or even just SDK (not publicly documented) global variables.
Provide a public API which alters the values of these settings.
So in the situation mentioned in the question you need an SDK-internal "show log" setting and a public API to set it.
HTH

Related

Objective-C framework which can be adjusted in compiling time

More detailed explanation (for smaller version, check TL;DR in the end):
I created a framework that I made available in Github. In it, there are 7 Macros that define how the framework should be compiled. I can't just replace them with static const's because 6 of those Macros are used to remove some things from the framework in compiling time.
Those Macros may be divided in groups:
Group 1) Use framework when available
#define USE_THE_METAL_FRAMEWORK_WHEN_AVAILABLE true
#define USE_THE_OPENGL_FRAMEWORK_WHEN_AVAILABLE true
Those defines make the framework use the Metal and OpenGL frameworks even if they weren't added to the project. That's done using dlopen. More details below:
https://stackoverflow.com/a/24266440/4370893
https://stackoverflow.com/a/21375580/4370893
https://stackoverflow.com/a/1354569/4370893
I use this so those frameworks can be used only if they are available, so the dev can build his/her app for macOS 10.6 and still use Metal if it's available in the system. The problem is: if your app binary calls dlopen somewhere, you can't add it to the Apple Store (even if you don't really use the function that uses it), so users should be able to remove that from the code if they want. That removes some of the framework functionalities, but make it capable of being submitted.
Group 2) I'm importing the framework
#define IM_IMPORTING_THE_METAL_FRAMEWORK false
#define IM_IMPORTING_THE_OPENGL_FRAMEWORK false
Those defines make the framework really use Metal and OpenGL frameworks, without using dlopen. In that way, it can be submitted to the Apple Store and still use the features that were mentioned before.
Group 3) Behaviour changes
#define USER_NOTIFICATIONS_SHOULD_SHOW_A_BIGGER_ICON true
#define NSDEBUGLOG_SHOULD_PRINT_TO_A_DESKTOP_FILE_TOO true
The first one can also cause problems in the Apple Store, and the second one is only for debugging purposes.
And at last...
Group 4) Should be released in the Apple Store
#define I_WANT_TO_BE_RELEASED_IN_APPLE_STORE false
That one is used for that:
#if I_WANT_TO_BE_RELEASED_IN_APPLE_STORE == true
#define USER_NOTIFICATIONS_SHOULD_SHOW_A_BIGGER_ICON false
#define USE_THE_METAL_FRAMEWORK_WHEN_AVAILABLE false
#define USE_THE_OPENGL_FRAMEWORK_WHEN_AVAILABLE false
#endif
It automatically disables the three defines that may cause problems with the Apple Store.
Still, those who use Travis-CI for example are not capable of changing the framework unless they completely copy it to the project. To solve this problem (or at least reduce it), 5 of those 7 defines could be changed by a file in the main project, for example. If anyone has other suggestions that may solve the issue, I'm listening.
(Optional) If this could be done in a way that the user may be warned (by Xcode or by an error in compiling time) that he/she needs to set those variables that would be great, since this would avoid problems with users that may need to set those Macros.
TL;DR: Is it possible to change the values of some Macros within a framework without modifying the framework itself?
No. Make some method, that initialize yours module with some parameters. But anyway you are not able to use dlopen.

Add warning messages to ILineBreakpoint in Eclipse

I wrote custom remote debugger for a specific environment. However, the remote environment performs several optimizations that move or delete pieces of original code and therefore it can't accept all breakpoints. Before debugger session starts and connects to the remote runtime, we can't predict which of the breakpoints can't be set. I would like to keep these breakpoints as they are set in editor, but when the debugger starts, it must somehow tell the user that certain breakpoints are invalid. I think that these breakpoints should look different way, but I haven't found API methods for this purpose. I tried to set IMarker attributes such as IMarker.PROBLEM and IMarker.SEVERITY, but it didn't help. What is the best way to do this?
This code snippet from the Eclipse Debugger guide is probably what you are looking for:
public PDALineBreakpoint(IResource resource, int lineNumber) throws CoreException {
IMarker marker = resource.createMarker(
"org.eclipse.debug.examples.core.pda.lineBreakpoint.marker");
setMarker(marker);
setEnabled(true);
ensureMarker().setAttribute(IMarker.LINE_NUMBER, lineNumber);
ensureMarker().setAttribute(IBreakpoint.ID, IPDAConstants.ID_PDA_DEBUG_MODEL);
}
https://www.eclipse.org/articles/Article-Debugger/how-to.html
I've found solution by myself, but it looks like a dirty hack. It works only with IJavaLineBreakpoint, for another languages another solution required, but for now Java support is enough. IJavaLineBreakpoint had the isInstalled method that indicates whether the breakpoint is installed into some JVM. Unfortunately, you have no direct way to modity this flag. Internal implementation just exposes value of the org.eclipse.jdt.debug.core.installCount attribute. So, to set installed property of a breakpoint, you should do the following:
breakpoint.getMarker().setAttribute("org.eclipse.jdt.debug.core.installCount", 1);
Also, you can just increase/decrease this attribute the same way. However, I am not sure that this approach is compatible across versions of JDT.

How to use a preprocessor definition symbol in Xcode to do some actions

In my application i have worked for some part of the next version implementations,
So we need to prevent those some implementations for this version.
our superiors asked me to do with pre macro processor, having #ifDef, endif like that and you need to define the version number in buildsettings as preprocessor macro
I have added a user defined setting 'App_Version' in build Setting,
"
How do i use it like
#ifDef AppVersion 1.0
NSLOG (current version implementation)
else
NSLOG (NEXT version implementation)
Actually i was not much awair on it, so that my interpretation was poor
#if App_Version == 1.0
I don't remember exactly how new preprocessor macros are defined in XCode but I don't think that you are defining it correctly. See How do I define preprocessor macros in Xcode 4?
However, using preprocessor macros for such things is far from recommended.
You should
Create a method that will read the application version from the bundle
Call the method to check version and use standard if-elseif-else
With iPhone development I can't really imagine why would you use such a macro/method though. How many versions of an app do you want to build? All the applications I have implemented for iOS needed only 1 version - the latest one. I don't see any reason why would you like to build an older application version from current code.
Use a versioning system and if you are implementing features for the next version into current code, use a dedicated branch! Otherwise it's just a mess and your supervisor is ... not smart ... for not seeing it.
The compiler doesn't need (or want) to know anything about application version (it is information for the application submission process). This should not be done with preprocessor macros, unless you want to define your own (even then, I wouldn't recommend it). You should check the application version at runtime
[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"];
and prevent new features from being accessible in the current version based on that. More generally I would consider using branching models like git flow to handle things like that. What will happen when you have 3,4,5 ... versions to handle. The preprocessor macros will become a nightmare to manage.

GData causing an error message when running the profiler

So, my dilemma here is pretty much the fact that I have GData included with static headers in my file per the instructions found here: http://hoishing.wordpress.com/2011/08/23/gdata-objective-c-client-setup-in-xcode-4/. Everything compiles correctly and such and I can run the Analyzer just fine. The minute I try to run the profiler to check for leaks, it hits the attached error The service placeholder compiler flag should be replaced by actual service specifications as seen below:
I'm not %100 sure on what I need to do to make this an acceptable service.. or why it triggers this error. Implementing GData was already a not-so-fun walk in the park. (Thank you the guy who added his static tutorial in google's documentation.. lack of documentation). Does anyone know specifically what needs to be done and/or how?
From the docs...
There is a conditional set in the static library target as a reminder
to developers to define the needed services. For your project, replace
or delete the definition
-DGDATA_INCLUDE_nameServiceHere_SERVICE=1
in the Other C Flags section of the static library target's Release
configuration.

is there anywhere where I could start MobileSubstrate tweaks programming?

After a search here on the forum I found a question like that, and it redirected me to a tutorial which gave em some basic instructions on manipulating SpringBoard with CapitainHook.
To start I'd like to do it with normal %hooks only. Any hint where I could start?
This little introduction is meant for whoever has a minimal knowledge on Objective-C and knows what he is doing.
NOTE: I will refer to the theos install path as $THEOS. This could be ~/theos, /var/theos, /usr/theos... Yeah.
The most popular way of creating MobileSubstrate extensions, also known as tweaks, is using Dustin Howett's theos build suite. Details follow:
What is theos?
So, we should start with what theos is not:
The Operating System
A Greek God
A compiler
And of course, what theos doesn't do:
Teaches you how to code.
Creates tweaks without having you to think
Sets up a whole building environment and/or installs the iOS SDK.
Theos is a cross-platform suite of development tools for managing, developing, and deploying iOS software without the use of Xcode, featuring:
A robust build system driven by GNU Make, which makes its Makefiles easily deployable through everywhere with theos installed too.
NIC, a project templating system which creates ready-to-build empty projects for varying purposes.
Logos, a built-in preprocessor-based library of directives designed to make MobileSubstrate extension development easy and with optimal code generation.
Automated packaging: Theos is capable of directly creating DEB packages for distribution in Cydia, the most popular mean of package distribution in the jailbreak scene.
How to install theos?
On OSX: Have the iOS SDK installed and follow these instructions.
On iOS: Install the BigBoss Recommended Tools package from Cydia and run installtheos3.
On Linux: Find a mean to have the toolchain installed, and follow these instructions.
On Windows: Nothing is impossible, but if you actually manage to do so, please let me know. :P
How to use theos?
This is a very asked question and too vague. Since theos is a whole suite of development tools, it doesn't make sense to ask How to use it, but more specifically, to ask How to create software using theos.
First of all, always have the Theos Makefile Reference in hand. It covers the basics of creating a theos Makefile, and that includes solving your linking issues adding a framework or private framework to the project.
Now, you can either create your own Makefile from scratch, create your little theos clone/symlink and start coding, but theos makes this step easier. You can just use nic.pl.
A very simple example of running NIC to create something can be found here. It's very straight-forward and sets you up right-away for programming.
Now, here's where we start getting back to topic.
Creating a tweak with theos
First of all, do not run NIC when inside $THEOS/bin. NIC will create the project directory exactly where you're running it from, and it avoids any project being created in $THEOS/bin. Therefore, you'll end up with a simple error which can be avoided by creating the project directory somewhere decent.
Run $THEOS/bin/nic.pl and choose the iphone/tweak template. You will be prompted by simple information which you may well know well how to answer, except for the last field: MobileSubstrate bundle filter.
Since a big part of MobileSubstrate is not just the hooker (the library which switches original methods/functions with yours), but also the loader (the part which gets your hooking to be inserted into certain processes), you have to supply this basic information for the Loader to know where to load your tweak. This field is but the bundle identifier for the application where this project will be inserted.
com.apple.springboard, the default option is the bundle identifier for SpringBoard, the application which is:
The iOS Homescreen
The launcher/displayer of common applications
The iOS Status Bar
Handler of some high-level essential background processes
Therefore, there's where many tweaks take place, altering behavior from something as trivial as app launching to something like how the whole homescreen UI looks like.
Programming a tweak with Logos
Now, the directory generated by NIC will contain:
The Theos Makefile, where you'll change information related to compiling
The control file, where you'll change packaging-related information
A symbolic link (or shortcut) to $THEOS named theos/
The main code file, defaulted as Tweak.xm. It is already added to the Makefile for compiling, so you can start coding right-away with it!
On knowing what to do
Now, you don't have SpringBoard's source code laying around, and you can't guess what methods to hook from nowhere. Therefore, you need a SpringBoard header set. For that, you need to use a tool named class-dump-z and run it into the SpringBoard binary (which is inside the iOS filesystem) to obtain header files including all class declarations and its methods inside the application.
From that (a deal of guessing and logging a method call is involved) you can start messing around with what you want in a tweak.
Of course, if you are not hooking SpringBoard you can use class-dump-z as you would in other binaries, such as UIKit, MobileSafari, etc.
Note that for when reversing App Store apps, they'll be encrypted. You'll need to decrypt those (I am unfortunately not allowed to tell you how-to), and then just run class-dump-z on them.
On obtaining private headers
Stuff like preference bundles require the headers for private frameworks, in that case the Preferences framework's headers. Else you'll get endless missing declaration errors (as I guess you could assume).
Getting them has the same logic applied the previous step. Run class-dump-z on, at this case, the Preferences binary and throw the headers at your INCLUDEPATH. The INCLUDEPATH is where the compiler will go looking for headers you include like #include <stdio.h>. Yes, stdio.h is inside one of the directories which build a compiler's INCLUDEPATH!
When compiling with a theos Makefile, $THEOS/include counts as part of your INCLUDEPATH, which means, you can just throw your dumped headers over there and include them later.
(Note that class-dumped headers aren't always perfect, so you're likely to have a couple of header-related compilation errors which can be easily fixed with something like removing a #import directive or changing it, or adding a couple of declarations.)
Code tips
You can't link against SpringBoard, so whenever you require a class from SpringBoard you have to use either the Logos %c directive or the objc_getClass function, as defined at <objc/runtime.h> to get it. Example: [%c(SBUIController) sharedInstance], [objc_getClass("SBUIController") sharedInstance].
When not knowing what a method does or how something works in SpringBoard, try disassembling it with IDA or others. I use IDA Demo (<- noob!) for my disassembling.
Looking at example code is amazingly helpful for both learning and figuring out how something works inside SpringBoard or others (again..). Great people at GitHub to have a projects looked at are rpetrich, chpwn, DHowett, EvilPenguin, and of course way more.
To also find about how SpringBoard and other works (...), have a look at a class's article at the iPhone Dev Wiki!
Epilogue
Wait, where's the good part? Where do I learn about coding in Tweak.xm?
Well, the original question was actually How to start MobileSubstrate tweaks programming?. You're all setup, hopefully with all headers placed, ready to type in make and see your project magically compiled with theos.
All you need to do is now to actually dig into your headers or your disassembly and go hooking, calling, etc.!
Logos Reference contains exactly how to hook and use other features of Logos, and the MobileSubstrate article on the devwiki is also a great read.
In case there is any doubt, don't hesitate joining the irc.saurik.com #theos IRC channel. It's a great way to discuss theos-related topics and ask questions. I'm mostly there, along with other greatly smart people ;)
You are looking for Theos created by DHowett.. Theos allows you to make tweaks, but it doesn't give you everything you need. You don't get every header for iOS, so you have to class-dump-z the frameworks/private-frameworks from the iOS SDK. Get started here: http://iphonedevwiki.net/index.php/Theos/Getting_Started, or join irc.saurik.net #theos for more help. You can also look at my projects that use theos: https://github.com/evilpenguin
You sound like you're looking for theos. Take a look at this, it should help get you started.