How to make android jar library with inner xml (layout/string) - android

I am creating a library, which should be distributed as a jar file.
Public function is void SomeLibClass.showSomeDialog(Context context) and task library is dialog show with a complex View inside. No activity, nothing difficult.
The pattern using library - developer add it to your project, and call in one place SomeLibClass.showSomeDialog and enjoy the funny dialog.
Seems logical that the resources needed to render the dialog were inside the jar file(to avoid errors such as: jar updated, but no resources) - we need in jar file: layout, string, drawable, etc.
And i want call resource by Id, like when i make layout i continue write like android:text="#string/hello"
But this logical thing to do can not be obtained.. now i make all resources in jar file with prefix, but how to solve the problem with the same id in R.java?
Or am I wrong look, and this is all we have to somehow do differently? Wants to repeat a simple - all you need for the library was in it.

If you wish to distribute Android-compatible Java code with resources, you need to use an Android library project.
The upcoming r14 edition of the Android Developer Tools reportedly has the ability to package up a library project, including resources, as a JAR. r14 should be released soon -- I would wait until this is released and then see how to apply it to your project.

Related

Can someone actually explain the workings of Resource.Designer.cs?

I routinely have problems during project builds where Resource.Designer gets generated but will no longer compile. My search engine shows that I'm not the only one that has this problem, but I've also not found any reliable "fix" for when it happens.
For example, right now I have a project that works just fine, but if I add a reference to a NuGet library (that I created) then the app will no longer compile because of loads of errors in Resource.Designer.cs.
On another project, I simply upgraded Xamarin Forms and now I can no longer compile, again due to a load of errors in Resource.Designer.cs.
Of course the immediate issue is "how do I fix the errors in these projects" but really I want to understand what is fundamentally going on here. What causes Resource.Designer to get generated and regenerated? What algorithm is used to decide what items get put into that file? Why do we so often end up with a file getting generated that then cannot actually compile? Why is it not getting the references it needs for those items?
I'd really like to understand this at a fundamental level so that once I get past the current thing causing me headaches, I can avoid it in the future when it comes up again (and I most certainly will come up again).
Resource.Designer.cs is synonymous with R.java in Android. Which of course is an application's resources that are referred to by a generated constant Resource ID.
These items are usually defined in your Xamarin.Android's .csproj via:
<AndroidResgenClass>Resource</AndroidResgenClass> (This might be outdated)
or
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> (Current)
This is part of the Android Build process in which the aapt tooling will generate respective constant resource IDs per each resource defined in your project(res/ - Android, Resources/ - Xamarin.Android). These are then processed into binary form and embedded into the .apk. Thus the Resource.designer.cs is generated after a successful aapt.
It then goes a bit further to define a Resource in a specific Resource Type:
http://code.google.com/android/reference/android/R.html
anim
animator
array
attr
bool
color
dimen
drawable
fraction
id
integer
interpolator
layout
menu
mipmap
plurals
raw
string
style
styleable
transition
xml
Since aapt is called in the Android Build tooling, it is highly recommended to not manually invoke it unless you understand the complete Android build process.
https://developer.android.com/studio/command-line/index.html
As far as an "Algorithm", I don't think it's really that complex other than simply mapping a Resource ID to a resource as defined above. There are some complexities in the sense of Merging Resources in a project. For example a library project -> your application project:
The build tools merge resources from a library module with those of a dependent app module. If a given resource ID is defined in both modules, the resource from the app is used.|
If conflicts occur between multiple AAR libraries, then the resource from the library listed first in the dependencies list (toward the top of the dependencies block) is used.
To avoid resource conflicts for common resource IDs, consider using a prefix or other consistent naming scheme that is unique to the module (or is unique across all project modules).
https://developer.android.com/studio/projects/android-library.html#Considerations
Given the majority of people's issues with Resource.designer.cs, they typically come from a point of view of understanding where actual third-party Resources come from and how they are supported. Here are some tips that I personally use:
Ensure your Application project is compiled against the latest API version. Typically this will be the <TargetFrameworkVersion> MSBuild property. One of my colleagues has an amazing blog post that stands the test of time about this factor:
http://redth.codes/such-android-api-levels-much-confuse-wow/
Find where the Resource is coming from. Does it come from an official NuGet package? When was the Resource introduced into the Android framework? (Useful for mostly Material Design items).
For example, if I had an error message regarding colorPrimary, I might check what API it was introduced in:
Added in API level 21
https://developer.android.com/reference/android/R.attr.html#colorPrimary
Thus we now know we require API 21+ at minimum to use this item.
Take a deep dive into the dependencies you are loading into your project. You can use a decompiler like dotPeek to look through an assembly and see what Resources it's trying to give your project. Additionally you can look at the cache of respective .aar and view it's res/ folder. This is mostly useful for larger bindings like the Android Support / Google Play Services ones. For smaller projects, look for the /res string inside the decompiled .dll
For example let's take a look at com.android.support:appcompat-v7:24.2.1:
First we need to find the cache on our machine:
AppData\Local\Xamarin\Xamarin.Android.Support.v7.AppCompat\24.2.1\embedded\res (If you get stuck here on OSX, I wrote a guide awhile back about finding these paths here - https://developer.xamarin.com/guides/android/troubleshooting/resolving-library-installation-errors/)
So we can now look through all of the respective Resources this library is trying to give to us.
Finally the last item is that people tend to delete the Resource.designer.cs file from their project. After the aapt process is complete, it will generate a new one or it will fail on aapt. It is up to you to figure out whether that step passed or not (i.e. Check the main project Resources folder for the newly generated Resource.designer.cs file so you can re-include it into your project).

why so many folders in src ? Why does Android do it this way?

When I make an app with package name com.example.app, src/com/example/app/MainActivity.java is created automatically. I am new to Java and I don't understand
why it uses so many folders inside folders? Why isn't it just src/MainActivity.java?
In order to avoid namespace collisions and conflicts, it's a common best practice in Java nest source code within a folder structure that is the reverse of the internet site associated with it. If everyone created jar library files in the root /src directory, eventually you'd have a collision and the code wouldn't be usable.
For instance, if I have some fancy Android library and I provided a class called Button, in a Button.java class, and you also at times wanted to use some other library that also had a Button.java in /src, your project would not compile.
Thus, in order to let everyone have their own unique Button class, the convention that was adopted was for everyone to use their reverse domain name, followed often by the project name. So the Facebook SDK, fo instance, has /src/com/facebook/android/Util.java while my own project has /src/com/myapp/misc/Util.java and I can use and reference both in my source code.

Can I share code & resources between Android projects without using a library?

The standard advice for sharing code & resources between Android projects is to use a library. Personally I find this works poorly if (a) the shared code changes a lot, or (b) your computer isn't fast enough.
I also don't want to get into deploying multiple APK's, which seems to be necessary when I use dependent projects (i.e. Java Build Path, Projects Tab).
On the other hand, sharing a folder of source code by using the Eclipse linked source feature works great (Java Build Path, Source tab, Link Source button), but for these two issues:
1) I can't use the same technique to share resources. I can create the link to the resources parent folder but then things get wonky and the shared resources don't get compiled (I'm using ADT 21).
2) So then I settle for copying the shared resources into each project, but this doesn't work because either. The shared code can't import the copy of its resources because it doesn't know the package name of the project that uses it. The solution I've been using is to access the resources dynamically, but that has become cumbersome as the number of resources grows.
So, I need a solution to either (1) or (2), or I'll have to go back to a library project. (Or maybe there is another option I haven't thought of?)
Your real problem is (2). Fixing (1) would eliminate some copying, but you would still run into problems with (2).
Unfortunately, that really isn't possible. There's a fair bit of fancy footwork that goes on to make multiple packages possible with library projects, and there's no good way to get that same result without library projects. Anything in res/ of a project is accessed via that project's R class, including your copied resources.
The solution I've been using is to access the resources dynamically
I translated that into you using getIdentifier(). That certainly works. Another approach is to having the hosting app supply resource IDs as parameters to the library code -- this is the pattern that the Android SDK itself uses. This is faster at runtime than the reflection-based getIdentifier(), and it gives the hosting app somewhat more flexibility, but you do wind up adding a bunch of parameters to your methods and constructors as needed to supply the various project-specific R values.

Custom build script to avoid libraries name collisions?

When using Android libraries if more than one project (main or libraries) defines the same resource, the higher-priority project's copy gets used and replaces the previous one.
This is a problem when writing a reusable library because it forces you to prefix every resource name to avoid conflicts. See the Android Parcel Project for more information on the topic.
Now what I'd like to do is a script that would, prior to compilation, prefix the name of every resource from all libraries with their package name. For this I intend to use the generated ant build script and add a custom step to it.
Do you know if that would be possible? Do you see a better solution to fix this issue?
Do you know if that would be possible?
If you have source code to the library, I suppose you could do this. Any place you refer to resource IDs dynamically (reflection, getIdentifier(), etc.) would have to be adjusted manually, I suspect. And you may not be able to get assistance from the library author given that you modified their code.
I'd also work on trying to convince the library author to add resource prefixes in future editions of their library.

Building an android library and passing the client's R.java when making the library call, how?

I would like to build a library and be able to distribute it as a jar without having to give the source. In the library, layouts are used for specifying the UI, however android doesn't seem to facilitate easily bundling a jar and distributing it, as it doesn't properly scope the resources (anything in '/res/*') in this jar file, the references made with R.xxxx within the jar don't work.
I can give the xml layouts and other resources to the client and ask them to put them into their resources directory, thus their R.java would have these references, now, how can the client pass this R.java to the library when invoking a method in the library?
Guess, answer to part of the question would be through answer to 'How to pass class in java?"
Yes, I am new to android and java too.
Thanks,
Krishna
If you have just simple layouts you could also create them in Java and not define them in XML.
It's not so nice but you don't have to distribute some other files.

Categories

Resources