How to make future-proof project with Carthage - ios

I have a project in which I use Carthage for my dependency management. I want it to be easy to clone and run right away for Future Me©. I'm commitning Carthage/Checkouts already, but some frameworks come with a prebuild binary. You can force downloading sources with ‑‑no‑use‑binaries flag, but adding a framework file would be easier. What (and why) should and should not be in my .gitignore to make the project future-proof?

Related

Save packages downloaded by SPM into project GIT using Xcode 11

I started using new Xcode 11 which integrates SPM.
I added first dependency to my project:
but detected that files are not fetched into my project folder but into Xcode's cache:
I would like to commit all my dependencies files into my main project repository so my question is:
Is it possible to change location of fetched packages via SPM using Xcode 11?
It's somewhat possible, although the solution isn't necessarily a good or great practice, so I can't recommend.
Set the DerivedData in workspace settings to be relative to the workspace.
Add gitignore rules such that the workspace/WORKSPACE_NAME_DIR/SourcePackages/checkouts and related files are includes. Maybe best to ensure repositories directory is not included.
Add a Run Script phase to remove .git and .gitignore files in the checkouts directory.
Obviously, this is fragile largely through fighting the way SPM works. The workspace settings are per person so it's not great in teams.
SwiftPM integration has been setup to prevent this. It clones the files into a DerivedData/ProjectName-[RandomStuff]. You should commit your Package.resolved into the repo to ensure that you get the same version of each dependency across clones of the project.

Carthage dependency build with custom flags

I'm debugging a memory corruption issue in an iOS application using Carthage for dependency management.
The problem is most likely related to a 3rd party dependency. I've rebuilt the dependency with -configuration Debug but that didn't give me any more data.
What I'd really like to do is compile it with -fsanitize-address which will hopefully pinpoint the exact moment things start going wrong. Unfortunately I don't see how to do this with Carthage. Is this possible?
You can modify the dependency's source code and project in Carthage/Checkouts. Just open it up in Xcode and tweak away to change anything you like. Then do carthage build to update the frameworks in your project.
Just be aware that the next time you do a Carthage update it will blow away any of the mods you've made. Carthage/checkouts only contains exported versions of the dependencies. Not git repos.

Is it possible to distribute binary ios framework using carthage

Please bear with me because I spent considerable amount of time on this. I am also relatively a beginner with swift and iOS.
What I did
- built a framework using cocoa touch
- clean, build and it succeeds without a problem.
- made the scheme shared
- did carthage build --no-skip-current
- did carthage archive
- copied only the zip file to a fresh new directory and uploaded with release in git.
- In a different project tried to pull the framework using carthage
and I get the error Dependency "xxx-ios" has no shared framework schemes then I copied the scheme directly and pushed it in the git along the zip. nothing. Tried without the zip together with the scheme. nothing.
Then I created a fresh framework and I did carthage build --no-skip-current and I uploaded the whole thing in the project folder to git. That pulls properly with carthage. Then I removed some part of that folder so that the scheme inside .xcodeproj and the carthage build folder remain, then I get a different error. At this point it got me thinking if carthage does support binary framework distribution.
In my company, they want it so that I don't expose the code - so I am trying to distribute built binary of the framework.
I would really appreciate any help or guides of what different things I could try to single out the problem. Thanks.
Edit
someone had almost exactly the same issue as mine in their issues here but a couple of conversations later it is closed without a solution.
It sounds like you're using a github dependency in your Cartfile and attaching a binary of your framework to the GitHub Release. But you don't have any code in the repository, so Carthage is complaining because it can't actually build it.
That's as designed—Carthage doesn't support distributing binary-only frameworks that way. Binaries attached to GitHub Releases are only meant as a way to speed up builds.
However, Carthage does have a mechanism for binary-only dependencies: binary dependencies.

Xcode framework Versions/Current/Headers/ error

I am confused about adding a third party framework into Xcode project.
Here are the steps:
1) I copy the framework into project subfolder called "Frameworks". So framework is added to repository.
Everything works fine, app compiles, here is the screenshot:
2) I push the changes into repository (I use mercurial)
3) If I pull the changes on other machines or just switch between branches then project doesn't recognize this framework any more.
Here is the screenshot:
The question is why it happens and how to solve this problem? I there any specific way to add a framework in this case?
Thanks in advance!
I had this problem today and it was because the 3rd party framework was delivered as a .zip file and symbolic links inside of the framework were lost at some point.
Here is Apple's documentation on the anatomy of a framework:
https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
The document explains that multiple framework versions might exist inside of the framework bundle, so the bundle contains some symlinks pointing to the current version of some directories.
MyFramework.framework/
MyFramework -> Versions/Current/MyFramework
Resources -> Versions/Current/Resources
Versions/
A/
MyFramework
Resources/
English.lproj/
InfoPlist.strings
Info.plist
B/
MyFramework
Resources/
English.lproj/
InfoPlist.strings
Info.plist
Current -> B
The problem you have is exactly like mine. Confirm that the three symlinks that Apple documented (MyFramework, Resources, Versions/Current) are not symlinks, but are tiny files. Then delete the tiny files and replace them with symlinks to the current framework version. For example, if the current version is 'A':
cd NewRelicAgent.framework
rm Headers
rm NewRelicAgent
rm Versions/Current
ln -s Versions/Current Versions/A
ln -s Headers Versions/A/Headers
ln -s NewRelicAgent Versions/A/NewRelicAgent
If there are multiple versions in your framework, then the text in Versions/Current might contain the current version. This would be an artifact where the compression tool is storing the symlink as text instead of an actual link.
We are facing a similar kind of issue. The result we get is the same, but the setup is different.
Posting our findings here, incase someone else finds it useful.
Our apps high level setup
React Native app
Git repo
npm for package management (npm install)
lots of .xcodeproj under one .workspace
one of those .xcodeproj have a .framework that shows the issue mentioned above
Our findings (so far)
it's not the actually git checkout thats causing this stripping out of symlinks in .framework behaviour
it's actually how our package manager (npm) installs the said sub repo. It might be npm is doing something to strip out symlinks in install or post install phase.
If we download or git checkout the said sub repo manually, framework symlinks are in tact.
Our initial approach to fix the issue
Include a symlinks intact version of the framework (Valid.framework) in the main project.
use npm install to install the packages as normal (this would strip out the symlinks in the framework Broken.framework file thats in the sub repo)
have a post install script copy and/or override Broken.framework with Valid.framework
cp -Rf <path_to_working_framework>/Valid.framework/* node_modules/<path_to_broken_framework>/Broken.framework/

Working with git submodules/cocoapods

I am working on a project which includes other repositories from Git.
I would like to keep up to date with these repositories. Know what are the latest features, bug fixes etc.
Qu 1) What is the best way to keep up to date with a repository on Git without receiving emails of all issues reported etc?
After this is complete I would like to know the best way to include these into your project. I understand you can copy the source code into the project, but what are cocoapods/sub modules used for? For example, what is the correct way to update your project with the latest changes to that included repository?
Are there any GUIs for either of these methods as opposed to terminal?
Cocoapods is a great way to include other projects in your Xcode project. The Cocoapods project maintains a list of pod spec files for a many open source libraries, which specify where to download the code and how to integrate them into an existing project. As you noted, you'd traditionally have to add a git submodule, manually add the source files to your project, update your build settings, and so forth. Cocoapods takes care of all of this for you.
I'm not sure of a way to track updates for Github projects without also being notified about issues, but Cocoapods can certainly tell you if any of your 'pods' have become outdated. It's then one command to update them to the latest versions. That said, it's generally best practice to 'lock' your external dependencies to a specific version that you know works correctly.
Using Cocoapods
To get started, first install Cocoapods. You then simply need to create a file in your root project directory (the same directory that contains your .xcodeproj file) called Podfile. Inside, you can specify your target OS, and your dependencies:
platform :ios, '5.0'
pod 'AFNetworking', '0.9.1'
pod 'OHAttributedLabel', '0.1.1'
The example above is targeting iOS 5.0, and pulling in the AFNetworking and OHAttributedLabel projects.
Then, in the Terminal, change to your project directory:
> cd path/to/my/project
And run pod install.
> pod install
This will check out the latest version of your dependencies for you. It will also generate you a .xcworkspace file. From now on, when you work on your project, you must open the .xcworkspace, not the .xcodeproj file.
Inside your new workspace, you'll have your existing Xcode project and a new Pods project - this contains all of your third party libraries. Just build and run your app as normal, and the Pods project will also be built and included.
Some other useful Cocoapods commands:
> pod outdated
Will list all dependencies that have an update available.
> pod search query
Will search all known Pod specs for 'query'. Useful for finding new libraries!
Tutorials
Looks like Tutsplus have a nice tutorial on getting started with Cocoapods
There's a free episode of NSScreencast on Cocoapods
GUIs
I'm afraid I don't know of any GUIs for Cocoapods, but there really aren't many Terminal commands that you need to know. It's worth getting comfortable with the command line, as it's such a useful developer tool.
That said, as far as I know, Appcode (Jetbrains' alternative IDE for Objective-C) is planning on adding Cocoapods support in their next update.
Good luck!
James Frost's answer is an excellent explanation of how to work with Cocoapods and their advantages over submodules.
A few important advantages submodules have over Cocoapods are:
submodules are sub-repos - not only does this mean that git and git GUIs implicitly recognize them and more and more support easily working with them, it also means that your dependencies stay connected the wonderful world their git repos, Cocoapods or not, reside in. This means that you are able to collaborate and test changes from within your project, your project usually being the source of inspiration for elaboration of a dependency.
Unfortunately Cocoapods do not maintain this link, to work on a dependency means to clone it from git, outside of the range of Cocoapods.
Edit: It's worth noting that Cocoapods does allow working on a local pod with the path or local fields or even building your own Spec repo but it still isn't as simple a process.
one less tool dependency - as mentioned in the previous bullet, submodules are a function of git and your using git means they are available to you. Any software's adoption of git implies that they will eventually support either all (important) features of git or all features that cover common use cases. Xcode 5 has brought in a basic support for git and GUIs (which are tool dependencies, it's true, but hopefully just dictate how information is surface, git dictates how it works) like Git Tower make working with sub-repos straightforward.
Cocoapods has come a long way and everyday is taking steps to becoming a stable, indispensable tool. However it hasn't yet gotten a nod from Apple and there isn't any reason why Apple won't release a change to Xcode that breaks Cocoapods. Additionally Cocoapods is dependant on Ruby. Aside, considering how much attention and community has been generated around Cocoapods it would be silly for Apple to ignore it.
It's also worth noting that using one does not lock you out of using the other. It might be a headache or it might be what you need, perhaps using Cocoapods for tiny one class libraries or libraries with complex dependancies and submodules for libraries with that you will be interacting with often.

Resources