How to create a 2nd app from a 2nd target in XCode? - objective-c

So I created a simple project, which I can test as an iPhone app. Now I'd like to make a slight variation of it, with an iAd. I was able to duplicate the target and test to the iPhone, by managing schemes (http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/Building/Building.html).
The issue is that no matter what scheme I test, I overwrite the other app. I'd like to be able to have two apps
AppName
AppName (Free)
living at the same time on my phone.
I want to avoid duplicating source files, because only the storyboard and the view controller are different, they both use the same images and model otherwise.
Any help is welcome!

Have you tried changing the bundle identifier in the new target you just created? So your full version would have bundle identifier: "com.yourcompany.AppName" and your lite version will have a bundle identifier of: "com.youcompany.AppNameLite"

I'm not currently on my Mac partition so sorry if I'm a bit off.
I would add a new configuration for your app. Call it something like "Release Free". Add a gcc preprocessor symbol "FREE" to this configuration.
Then everywhere you initialize and instantiate your iads put the code within some "#if" statements.
Something like this.
#if FREE
// Init iAds
#endif

Related

Xcode cannot find ProductModuleName-Swift.h

I'm attempting to import my "-Swift.h" file into one of my Objective-C .h files but xcode keeps telling me that the file doesn't exist
#import "Aesculus-Swift.h"
If I command click on the file name it will take me to the generated header file so I know it exists. Why is xcode not able to find it?
This seems like just another issue with Xcode and it's complex tool chain of static analysers and compilers.
Openradar lists radar://21362856 - Swift to Objective-C bridging is unreliable. I am sure there are more but I stopped looking after finding one for this example.
The author imarcelv notes in the description:
I asked a Swift engineer at WWDC in a lab and even he didn't know how to fix this issue.
Steps to Reproduce:
Add a ramdom Swift class to an Objective-C project
Add the #import "ModuleName-Swift.h" file that Xcode generates automatically
Try to use it or just try to compile the project
From time to time it simply doesn't work
It's probably best to file a radar on this issue as it seems that others are already calling it out.
One other thing you could try...
Historically, it was possible for Xcode to completely lose it's syntax highlighting and you could always find out what files the static analyser was giving up on by increasing log level of clang.
I'm not sure if it's still relevant but if I was in your position I'd be trying this command:
defaults write com.apple.dt.Xcode IDEIndexingClangInvocationLogLevel 3
This generates logs you can search with using Console.app for just xcode to highlight the messages. You'll want to trash the derived data of your project to force it to re-compile things.
Although not the same issue as what you're seeing, I have had this post on the syntax highlighting issue bookmarked for years for the above defaults write command to try in times like these.
I solved this recently by adding the following entry to my .xcconfig (you could add it in Xcode's Build Settings > User Header Search Paths if you prefer).
USER_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/MyFramework.framework/Headers
This tells the compiler to search for headers in the build output directory, which is where Xcode puts the generated header (at least in the case of this framework).
In my case this is a directory like ~/Library/Developer/Xcode/DerivedData/MyProject-LongCode/Build/Products/Debug-iphonesimulator/MyFramework.framework/Headers/MyFramework. You might find your generated header in there too.
Xcode's header and dependency management is a hot mess, and it's not surprising that it doesn't work for you.
I had trouble with this stuff & found that your -Swift file is the Product name of your Target ( not just the name of your Target ) . I found the details here helpful: http://ericasadun.com/2014/08/21/swift-calling-swift-functions-from-objective-c/
When you encounter such situation, just find your kinda "ProductName-Swift.h" file by just cmnd+click on it (even if xcode shows warning about it is not found, the #import "Aesculus-Swift.h" string is still clickable) and then in opened code editor window choose context menu and "Show in Finder" item, then explicitly add it to your project.

How to intercept reading of plist values in Objective-C code?

We're using the new Urban Airship iOS plugin for PhoneGap.
In the plugin's plist file, we're supposed to enter the app-specific keys needed to enable push notifications.
The problem is we have two versions, free and paid, of the same app, but the plist file only accommodates one version.
Essentially, we need to modify the Objective-C code to read different plist values, depending on whether it's the free or premium version.
We currently manage both versions with the same code base and Xcode project. Unless we change the plugin code, it seems like we need to create a new Xcode project, which we don't want to do.
How do we adjust Urban Airship's Objective-C files to read different values from the plsit file?
Sorry to keep you waiting, I wanted to give you a very detailed answer instead of rushing last night :) So here we go.
First in your project we need to add a new target. Go to your project settings and right click your target. Click duplicate.
You'll get a new target probably named Target-copy. You'll also get a new info.plist file just for that target.
Next we're going to edit our Pro version's Built Settings. Scroll or search and find Apple LLVM compiler 4.0 Preprocessing. Add to both your Debug and Release configurations. I normally just go with the simple PRO=1. You also need to add PRO=0 to your lite version or it will be undefined when you try to build that version.
Now lets look at how to add a custom plist like I'm sure you'll need. First create two folders. Its important these are folders not groups. In each folder we can create a plist with the exact same filename.
Since Now you can add something to each of them. I just added a key property and a value pro string / lite string. Finally to the code. In the sample project I made I simple overrode viewDidLoad but obviously this will work anywhere. Since the plists have the same name you can load them with one line of code. They'll never get mixed up because they are only copied to their respective target. If you need to do code level based logic you can use the PRO preprocessor we made.
- (void)viewDidLoad
{
[super viewDidLoad];
// This will load the proper plist automatically.
NSLog(#"Plist Value: %#",[[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Property List" ofType:#"plist"]] objectForKey:#"property"]);
// Also remember we set up a preprocessor PRO. you can use it as well.
if (PRO) {
NSLog(#"Only Show for Pro");
} else {
NSLog(#"Only Show for Lite");
}
NSLog(#"This will show for both");
}
This is the method I use for all my lite/pro version apps so I can share a common codebase without copying it between projects or other complicated systems. It has worked pretty well for me so far :) Happy Coding!
Source
Figured someone may be able to use the project to look at so here it is on GitHub.

iOS - Execute precompiled app from a server

I'm looking for executing a .xib (with its own controllers and libraries) precompiled on a server, downloading it on runtime.
Is it possible?
Thanks!
EDIT:
So could somebody give me an example of a program that uses NSBundle that executes other app?
And how do I create the bundled application?
I don't think you can import a xib into the application's bundle at run-time (which you would have to in order for this to happen). Others may know more and correct me!
I can think of a couple of ways you could try to do this, but are you aiming to get it in to the store?
This is expressly prohibited by Apple Developer Guidelines.
A .xib file is just a data file, so there shouldn't be any problem loading one that's outside your app's bundle. I can't say I've ever tried it, but as long as it's in a bundle, you should be able to:
Create an instance of NSBundle using the path to the bundle containing the .xib you want to load. See +[NSBundle bundleWithPath:] for that.
Load the .xib using the bundle you created in the previous step with any of the normal .xib-loading methods, such as -[UIViewController initWithNibNamed:bundle:] or +[UINib nibWithNibName:bundle:].
with it's own controllers and libraries
That part won't work. iOS doesn't allow dynamic linking to frameworks other than the ones provided by the system, so there's no way to load your code. If you can build all the code you need into your app, though, you should still be able to use downloaded .xib's as described above. That would let you do things like update the way your views are laid out or what targets and actions your controls are connected to.

Multiple apps from one project

I have a little problem.. which I know there is a fix for, I just don't know what it is.
The problem is the following. A few weeks ago (2 or so) I had to remove 4 apps from the appstore due to a data problem on my server side. I decided to upgrade all the apps to the latest version at the same time giving them some new features. (I have 6 of the same apps out there, targeting different airports). The difference between these versions are the following:
A set of 50-80 or so images that combine the map of each airport. The filenames are the same in each app. (How do I solve that?)
The name of the app
The Default.png (and those for iPad and retina of course)
The App Icon
The content of a details page (which exists in a .plist file)
The content of the "About" page where the page refers back to the app
Some localize content, refering back to the airport the app targets.
The provisioning profiles, of course.
Keeping track of these things are just a pain in the ass, so I want to have 1 project with 1 code base and just add the images and details (mentioned above) and new versions appear. When I "Archive", I want all of the apps to be build and ready to be send of to apple (which I will have to do manually).
How can I achieve this?
I have done this before using multiple targets and conditional compilation. You need one target per deliverable. You can configure the name, icons etc for each target in the usual way.
A set of 50-80 or so images that combine the map of each airport. The filenames are the same in each app. (How do I solve that?)
Keep the images in different directories and for each target only add the images for that app. This technique will also work for the contents of the about page if you can load that from a file.
I also use conditional compilation so that I can define different values for my constants for each app.
To do this add a setting to Other C Flags and Other C++ flags to identify your app. Something like:
-DAPP_VARIANT=1
In your code you can then use the following to implement any app specific behaviour:
- (id)init
{
#if APP_VARIANT == 1
self->server_url = [[NSURL URLWithString:#"http://app1.example.com"] retain];
#elif APP_VARIANT == 2
self->server_url = [[NSURL URLWithString:#"http://app2.example.com"] retain];
#endif
}
Can't you use one version control branch for all the main code, then fork it six times (once for each airport) where you fill in the data? Once you make new code changes, just push the changes from the main branch to the forks and you're done.

What are the steps to creating an 'executable bundle'

I'm trying to create an NSService in a Bundle project. I need to add a main and other bits of code to the actual cocoa bundle created for me by xcode.
Is this as simple as just adding an object-c class via the xcode wizard, then adding my main function to that? or is there some other magic way or other steps involved?.
Many thanks.
You can add code by simply adding source files.
A bundle normally does not have a main function since it is loaded from another executable.
thanks Nikolia - after adding the code, i also had to change the bundle type to Executable, which also allowed me to change the extension from .bundle to .service.
Now all I need to do is work out how to stop the service!