i'm writing an android module, which i will include in some of my projects. Now i need to get the application name(at runtime), e.g. the name that is set as android:label for the application in the manifest. Obviously i can't use getResources().getString(R.string.app_name) because i can't access the resources of the project that uses this library. Is there another way?
I tried getApplicationInfo().name but that is null and i can't find anything else.
I tried getApplicationInfo().name but that is null
That is because name comes from the android:name attribute on <application>, and you are not using a custom Application subclass in your app.
i can't find anything else.
Call loadLabel() on the ApplicationInfo, passing in a PackageManager as a parameter, to retrieve the android:label value for an <application> or any component (e.g., <activity>).
The module is included in the application so I guess you are calling one of its methods in the application. If it is the case, I propose that you add a parameter in this method to get the context of the application. Then you can use context.getResources().getString(R.string.app_name) in your module to get the application name.
Related
I'm building a sample multi module app where I have 1 library common, which has a MainActivity and a simple TextView. The TextView has no text defined in the xml and the MainActivity has binding.tvText.text = getString(R.string.url).
I have 2 modules google and facebook, where there is no Activity, their manifests include:
<activity android:name="com.example.common.WebViewActivity"
android:exported="true">
and I have listed the library common as a dependency for both modules (implementation project(path: ':common')). The TextView appears blank, when it should show either www.google.com or www.facebook.com, but what's interesting is that if I set the xml's text to #string/url, it works perfectly for both modules. Even changes like textColor aren't reflected in the MainActivity!
This is an issue as I want to load a WebView in the Activity with a different url for each module, but none of the changes are picked up. Any advice?
Each module has it's own R resources class that references the resources in that same module. When you use R.string.url in your runtime code, it is explicitly pulling the com.mybasemodulepackage.R.string.url resource, not some resource that might be defined in some other module.
When you use #string/url in your XML, the layout inflator pulls the resource from the closest resource scope, the one from the package name that the app was built with.
I'm not sure of the best solution, if setting it in XML is not appropriate for your situation. You might have this common activity acquire the URL from the extras passed to it. Then each module can pass the URL when they open the activity.
I am attempting to bind a jar file to a Xamarin bindings project. For a particular field, the global keyword needs to be used in order to avoid ambiguity between 2 namespaces (com.paypal.android & android.widget).
Error CS0234: The type or namespace name 'Widget' does not exist in the namespace 'Com.Paypal.Android'. Are you missing an assembly reference?
Xamarin is smart enough to include the global keywords within the field's getter and setter; unfortunately, Xamarin isn't smart enough to to include it in the field's type:
public IList<Android.Widget.TextView> C {
When I alter the code itself, it gets overwritten when I rebuild the project. I believe I need to add the global keyword inside the Metadata.xml (although, I'm not quite sure how).
I've attempted to add the following in order to change the return type:
<attr path="/api/package[#name='com.paypal.android.sdk']/class[#name='cD']/field[#name='c']" name="managedReturn"> NOT SURE WHAT GOES HERE </attr>
I'm writing a library that is used by developers and I have a configuration items like apiKey, environment and others. I want to developer to set these values, my first thought was using Java Properties file that I load in the Application class, but I've seen Google Play and Google Map SDK ask the developers to add their apiKey in meta-data tag in Android Manifest. What is the recommended way?
The recommended android way to let the user define values for your library
from the application module is through meta-tags
it is as easy as using this code on the android-manifest
<meta-data android:name="com.yourproject.apikey" android:value="apikey"/>
and you can get these values from your library like this
try {
ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(activity.getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = applicationInfo.metaData;
String apiKey = bundle.getString("com.yourproject.apikey");
} catch (NameNotFoundException e) {
//Resolve error for not existing meta-tag, inform the developer about adding his api key
}
The main benefits of this approach are
1) That you can let the user define different values per device type e.g. phone, tablet or sdk-version
(this may not be applicable for your case but it's a good point for sure)
2) You can add complex data as the value in your meta-tag,
and you can use this if you want to add a string-array with all the value that you want to declare.
3) Since meta-tags are basically a bundle it is easier for you to
Read these values on your library code.
Have default values if the user has not declared the required
meta-tags.
(I believe that parsing properties from assets requires more code without any great advantage)
4) You can also add configuration meta-tags for activities,providers and broadcastreceiver on your AndroidManifest.
5) Also I suppose that it is easier to request for the consumers of your library to add a few meta info on his Android Manifest, than adding a properties file on their assets folder.And i believe that this is the main reason Many known libraries use this approach like google-play-service, google-maps, crash reporting libraries and many libraries that provide user analytic.
Good Luck
It´s seems that using meta-data tag is the Android way to achieve this, although I can´t find any official documentation to argue why.
Using meta-data you can define you property value using a resource instead of a static value, this way you can get different values for the same property based on the resources qualifier. This is very useful if your property needs internalization.
Ex:
<meta-data android:value="foo.bar" android:name="#string/hello" />
is easy using this
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="API_KEY"/>
My application depends on a library project.
The menu.xml file is within the application project.
All the java code is within the library project, including the menu handler code onOptionsItemSelected().
Is there a way to access the application resources from library project ? I'd like to write something like this, which is currently impossible, since menu items are not visible from the library:
if ( item.getItemId()==R.id.settings ) {
...
}
Yes you can if you know the package name of your library. See: Resources#getIdentifier
You can do:
getResources().getIdentifier("res_name", "res_type", "com.library.package");
ex:
R.id.settings would be:
getResources().getIdentifier("settings", "id", "com.library.package");
You should really just include a version of the menu.xml resource in your library project. If you want to have a different menu.xml in your application, you can do that and it will override the copy from the library project.
From the Library Projects docs:
In cases where a resource ID is defined in both the application and the library, the tools ensure that the resource declared in the application gets priority and that the resource in the library project is not compiled into the application .apk. This gives your application the flexibility to either use or redefine any resource behaviors or values that are defined in any library.
I found #triad's solution with Resources.getIdentifier(String, String, String) to be somewhat error-prone:
the String-literal resource identifiers aren't checked by the IDE
multiple sequential String arguments to a single method are easy to use incorrectly.
I found this approach to work better for me:
String libString = context.getString(example.library.pkg.R.string.library_string)
Where the library's package is example.library.pkg.
The library's R class is resolved at compile-time, so your IDE will tell you if you referenced it correctly
Not importing the library's R class allows you to still use your own local R later,
and explicitly marking the external resource usages makes them easier to spot.
I have a ContentProvider in my manifest, when I define them fully with hardcoded strings it works. E.g.
<provider android:name="com.myprovider" android:authorities="com.myprovider"/>
Works perfect, however the ContentProviders are in a library that gets used by multiple projects, and I don't want authority conflicts, so I attempted to do the following.
<provider android:name="com.myprovider" android:authorities="#string/myProviderAuthority">
This way I should be able to define all my authorities in a single strings.xml file and not have conflicts between apps since I should be able to change them using each apps resource override system.
However, it appears that when I try to build with #string, it gives me a malformed manifest error and says "Provider does not INCUDE (yes it says INCUDE) authorities tribute"
Can I not use a resource string for the authorities tribute, I feel sick everytime I need to maintain constants in two locations. Authority conflicts can be hard to catch by our QA dept, and I don't want things to become out of sync or it could cause confusion. Anybody have any ideas why my code isn't working?
I faced a similar problem but with the android:versionCode attribute. When I tried to define the version code in resources and use a reference to it in the manifest Android Market even forbade me to publish the application. The reason of such behavior turned out to be rather simple. Resources can change depending on current configuration and this value have to be the same in any case.
Probably, this is the reason why content providers with authority references do not work too. And it seems to me that it's not a good idea to use such a reference because there's no guarantee that there will be the only one value for an authority resource in an app. I understand that you can be careful enough to keep a single instance of this resource but there's no special compiler or system checks for this so it cannot be trusted.
Many manifest attributes cannot be specified as a reference to a string -- they must be specified as explicit string values.
The code that parses the manifest is in: frameworks/base/core/java/android/content/pm/PackageParser.java. That class calls, among others, getNonConfigurationString() and getNonResourceString() (which are implemented in: frameworks/base/core/java/android/content/res/TypedArray.java).
getNonConfigurationString() describes itself as:
Retrieve the string value of an attribute that is not allowed to change with the given configurations.
getNonResourceString() describes itself as:
Retrieve the string value for an attribute, but only if that string comes from an immediate value in an XML file. That is, this does not allow references to string resources, string attributes, or conversions from other types. As such, this method will only return strings that come from attributes in an XML file.
The manifest attributes that PackageParser doesn't allow to be taken from resources or from different configurations are listed below.
These attributes are defined in com.android.internal.R.styleable The manifest.xml element attribute name is usually the part of the name after the last '_' in the formal name. For example, the android:authorities attribute in a element in manifest.xml is AndroidManifestProvider_authorities, or com.android.internal.R.styleable.AndroidManifestProvider_authorities. (The number in the lists of attribute names below are the line number of the relevant code in version 4.1.1 of PackageParser.java)
Attributes read by getNonConfigurationString:
917: AndroidManifest_versionName
922: AndroidManifest_sharedUserId
2057: AndroidManifestActivity_parentActivityName
2071: AndroidManifestActivity_permission
2079: AndroidManifestActivity_taskAffinity
2247: AndroidManifestActivityAlias_targetActivity
2330: AndroidManifestActivityAlias_permission
2336: AndroidManifestActivityAlias_parentActivityName
1672: AndroidManifestApplication_name
1683: AndroidManifestApplication_manageSpaceActivity
1697: AndroidManifestApplication_backupAgent
1795: AndroidManifestApplication_permission
1800: AndroidManifestApplication_taskAffinity
1815: AndroidManifestApplication_process
3005: AndroidManifestData_mimeType
3017: AndroidManifestData_scheme
3023: AndroidManifestData_host
3025: AndroidManifestData_port
3031: AndroidManifestData_path
3037: AndroidManifestData_pathPrefix
3043: AndroidManifestData_pathPattern
2527: AndroidManifestGrantUriPermission_path
2533: AndroidManifestGrantUriPermission_pathPrefix
2539: AndroidManifestGrantUriPermission_pathPattern
2579: AndroidManifestPathPermission_permission
2581: AndroidManifestPathPermission_readPermission
2586: AndroidManifestPathPermission_writePermission
2615: AndroidManifestPathPermission_path
2622: AndroidManifestPathPermission_pathPrefix
2629: AndroidManifestPathPermission_pathPattern
2434: AndroidManifestProvider_authorities
2441: AndroidManifestProvider_permission
2443: AndroidManifestProvider_readPermission
2454: AndroidManifestProvider_writePermission
2713: AndroidManifestService_permission
2832: AndroidManifestMetaData_name
1225: AndroidManifestOriginalPackage_name
1981: (parsePackageItemInfo -- I can't tell list of all names)
3258: (Component constructor args.nameres -- I can't tell list of all names)
Attributes read by getNonResourceString:
1806: AndroidManifestApplication_taskAffinity
1821: AndroidManifestApplication_process
1632: AndroidManifestInstrumentation_targetPackage
2891: AndroidManifestPackageVerifier_name
2894: AndroidManifestPackageVerifier_publicKey
1512: AndroidManifestPermission_permissionGroup
1200: AndroidManifestProtectedBroadcast_name
1927: AndroidManifestUsesLibrary_name
1054: AndroidManifestUsesFeature_name
1004: AndroidManifestUsesPermission_name
3308: (Component constructor args.processRes -- I can't tell list of all names)
So, alot of attributes in the manifest.xml file must be specified as explicit string values (ie in quotes) rather than references to strings in strings.xml.