Xcode - how to change file's target membership via command line? - objective-c

Is there a way to change file's target membership in Xcode project via command line?
Here's what I'm trying to do via Xcode's UI:

I also had to do this for CI. After lots of digging, I do not believe this is common enough for anyone to have written a tool to help with doing.
The only conclusion I came to was to edit the project.pbxproj file directly, which is never a great thing to do. None of the tools which claim to do this were of any help until I found this stackoverflow answer on editing the project.pbxproj file. Essentially, you can convert the project.pbxproj file into a JSON format using plutil -convert json project.pbxproj and use a JSON manipulation tool to make those files as headers then point them to be headers of whichever target you would like.
When converting the project.pbxproj into JSON format, be aware that Xcode will no longer be able to show you the project navigator for that project. It will still build and run, however, so this is really only useful if you're planning to do this right before building (such as for CI).
(EDIT: As of July 2022, Xcode will now properly read a JSON version of its .pbxproj to allow you to view your files in the project navigator. I'm not sure which version introduced this, but it is at least now possible with later versions of Xcode.)
The format project.pbxproj as JSON has nearly all the important data under the "objects" key. The file you want to be a header already has an entry with the key being the UUID for the file and a path value you can use to relate the UUID to your file. Here's an example of that format:
// UUID for your file
"65TYSSDXHSLP4UUOAD9D40C322AAGHM9": {
"path": "MyHeader.h", // Your file's name
"isa": "PBXFileReference",
"includeInIndex": "1",
"lastKnownFileType": "sourcecode.c.h",
"sourceTree": "<group>"
}
There's another entry to declare this file as a header, which has its own UUID and a reference to the UUID of your file:
// UUID for your file as a header
"YU3BSD39O9PT5RESDFV741D1": {
"isa": "PBXBuildFile",
"fileRef": "65TYSSDXHSLP4UUOAD9D40C322AAGHM9", // UUID for your file MyHeader.h
"settings": {
"ATTRIBUTES": [
"Public" // could also be Project or Private
]
}
}
Then finally, your target has a list of header files where you will want the UUID for the header reference to go.
"A82GAE9A5HUIO063IOPQAAQIUFGSNXZ": {
"isa": "PBXHeadersBuildPhase",
"buildActionMask": "2147483647",
"files": [
"YU3BSD39O9PT5RESDFV741D1" // UUID for your file as a header
],
"runOnlyForDeploymentPostprocessing": "0"
}
Again, changing the project.pbxproj file directly is never a great idea, but until there's a better tool for making these changes without using Xcode, it's the best I could find. If anyone else is aware of something I'm not, please let me know.

Related

How to access static/local files in react native

I'm not sure what to call the files, but the context is that I have a bunch of data that I would like to ship with my app. I need to find a way to store this data so that I can load it into the database. (Or better yet, just ship it with a prefilled db)
Here are the solutions that I've seen:
Storing the data in code as a json blob I can't do this because I have quite a lot of data, a few MB or so and I would like to be able to compress it.
Load a file from the public folder
I think this is a create-react-app specific API and I did not use that. But if there's a way to get a public or static folder to read arbitrary files from, that'll be great.
Read a file using react-native-fs
I'm not sure where to put the file in my application so that I can access it. This seems to give me an empty folder to write files to. I don't know where in my app directory I can put the files if I want it to be read by this.
I would also like to have these files compressed, and only loaded when I need them to be. I think using a require('path/to/file.json') loads the file every time I use the app.
How would I go about reading a file from my app?
I'm coding for android if that matters and the database I'm using is watermelondb.
You need to use react-native-asset to put files to your project and access them with require keyword.
Example for file with path ./assets/files/some-file.mp3:
Add or modify react-native.config.js
module.exports = {
project: {
ios: {},
android: {},
},
dependencies: {
},
assets: [
'./assets/files'
],
};
Run npx react-native-asset
Use the file:
const file = require('./assets/files/some-file.mp3')

emmet expression can't expanded in .vm file when use vs code

I change my editor to vs code recently and then setup a lot of plugins. I use velocity(.vm) in our project but use emmet to expand expression in a vm file with vs code.
It doesn't work and I try to slove it and find the source option file:
C:\Program Files (x86)\Microsoft VS Code\resources\app\node_modules\emmet\lib\snippets.json
Then add this in the bottom json
"vm": {
"filters": "vm",
"extends": "html",
"profile": "xml"
}
But it doesn't work too. So, I will ask that how do you solve this problem in your project module file (like .ejs .php...)?
Or if find the wrong place to modify the code ?
My Environment is: win 10 vs code 1.4.0
filter is a name of a special JS method that formats expanded abbreviation. It had nothing with a document syntax. In your case, you have to find out how VS detects syntax for .vm files and then ensure that this syntax is supported by Emmet. E.g. the name of the syntax might be “velocity”

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.

Include issue: header file not found in iOS project in Xcode 4

Consider my setup looks like this:
XCode 4 iphone/ipad project
ObjC .m file that includes a new header file, this header is reported as "file not found"
ObjC .m file is located in root folder of the project
new header file is also located in root folder of the project
new header file was created within Xcode 4 as "C header file" (!!)
I tried using #import and #include statements with both "" and <> lookup syntax.
The project already consists of a bunch of other objC headers/classes and they work nicely. I suspect that creating the file as a C-style header is the issue.
I did explicitly NOT try to add a USER_PATH or anything like that, since it's all happening in the root project folder.
Any ideas? I'm really surprised how complicated such simple things can get!
! Additional comment: (EDIT)
I now verified that I can create any type of header (menu "new file"->"C/C++"->"header") and it will never be found by objective-C code. Even a new clean project behaves the same! What kind of feature is this?
Weirdness.
I talked to a bunch of fellow Xcode sufferers and they confirmed I HAVE to set the extra path variable. Their explanation was a bit odd though: in objectiveC the lookup (import) simply scans the whole subfolder structure, whereas an 'include' does not. From my point of view this would only be a valid argument if the header file in question was located in a subfolder! But mine is in the exact same location as the '.m' file!