Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-11360] Tooling: Android module build scripts throw NoClassFoundException when native Android project is included as library which has UI built in XML

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2015-04-13T16:21:19.000+0000
Affected Version/sRelease 2.1.3
Fix Version/s2014 Sprint 09, 2014 Sprint 09 SDK, Release 3.3.0
ComponentsAndroid, Tooling
Labelsexempt, module_module, qe-manualtest, triage
ReporterAnirudh Nagesh
AssigneeVishal Duggal
Created2012-10-10T21:14:20.000+0000
Updated2016-06-17T12:46:35.000+0000

Description

Summary: If we include a native Android project as library to our Android module environment and try to access the library's functionality, it throws NoClassFoundException if the UI elements are built using XML layouts. Work Around: Build the UI components using Widgets ( java ). This is a laborious process as native android projects are built using layouts in xml. Steps to reproduce: -------------------- 1. Import the attached 'Sample-apklib.zip' to Eclipse/Studio 2. Build the project as a library ( jar file is generated in bin folder ) 3. Import the attached 'Sample_apklib_module.zip' to Eclipse/Studio. 4. Add the jar file obtained in Step 2 in the build path of Sample_apklib_module project. Also copy the jar file to 'lib' folder of the module project. 5. Build and run the module using ant scripts. 6. Exception is seen as UI elements in library is referenced in the module. Work Around: All UI elements should be created using native java methods ( widgets ).

Attachments

FileDateSize
sample_apklib_module.zip2012-10-10T21:14:20.000+00001662051
Sample-apklib.zip2012-10-10T21:14:20.000+000082653

Comments

  1. Perminder Singh Bhatia 2012-10-11

  2. Perminder Singh Bhatia 2012-10-16

    Chris, thanks for updating Fix Version. In the mean time, can we have a patch in order to resolve this issue in the current version ?
  3. Perminder Singh Bhatia 2012-10-16

    Also, please mark this bug with Priority as High as currently it carries None. Thanks.
  4. Chris Barber 2012-10-16

    @Perminder, I did not set the Fix Version and I unfortunately will not have a patch since this isn't my area of expertise. Whoever gets assigned this ticket will be the one to fix it.
  5. Perminder Singh Bhatia 2012-10-17

    @Chris - I checked the history and it was Ingo who updated the Fix version. @Ingo - can you please update on my previous comments.
  6. Ingo Muschenetz 2012-11-13

    Perminder--we cannot provide a patch at the moment. However, we will look at this in the 3.1 timeframe.
  7. Mehdi Bouamama 2012-11-21

    Hi, is it possible to have an ETA for this ? The future of my project depends on this feature. Thanks.
  8. Mark Mokryn 2013-10-07

    This is a critical piece of infrastructure that must be implemented for Android. Not being able to easily integrate Android library projects which have XML resources means that these library projects have to be hacked in order to work with Titanium. The corollary is that these projects become totally unmaintainable. A good example is the Facebook module. The Android Facebook SDK is totally hacked up because of this. Please try to fix this issue! Thanks.
  9. Mark Mokryn 2013-10-07

  10. Mark Mokryn 2013-10-07

  11. Sky Kelsey 2013-10-07

    I'd like to throw my vote in for this feature as well. I just finished adding support for our (www.apptentive.com) SDK on Trigger.io, and while this was not an easy process, it was possible. Android Library Projects are the only way to package a third party library while still leveraging the power of the Android resource management system. I doubt it will be cost effective for us to provide a Titanium module until this is supported. To put it another way: I, and many other third party Android developers who add value to the various web-to-native platforms, will be unlikely to rewrite our SDKs to fit into a JAR.
  12. Mark Mokryn 2013-10-08

    This feature is probably the #1 showstopper to porting 3rd party modules, but there are others, and thus the entire module API needs to be reviewed. I submitted an issue requesting that the iOS module API supply full access to application lifecycle events (e.g. access to handleUrl, etc). In Android, modules often need to have access to the full Activity lifecycle, including to onActivityResult (e.g. returning from Facebook login UI). Currently, there is only access to the root activity lifecycle, which is probably useless for most modules. Not having such access means that Titanium Android modules need to launch their own activities, instead of simply operating in the context of the activity that wants to use the module. An example of such convoluted logic can be seen here: http://stackoverflow.com/questions/5215071/appcelerator-custom-module-receiving-callback-for-onactivityresult
  13. Mark Mokryn 2013-10-09

  14. Martin Guillon 2013-10-28

    I actually managed to have actionbarsherlock (and appcompat before) working with Ti framework. I have it packaged with the framework then correctly used to generate and compile the app. I was abled to do that thanks to the new cli for Android. Thanks to a few line changes i had it working great. And it should work with any 3rdparty library. A little more work needs to be done to allow it inside submodules. But it s mostly there Will soon be published [here](https://github.com/Akylas/titanium_mobile)
  15. Allen Yeung 2013-11-14

    There might be some confusion on what this bug is about. The problem occurs when we try to include third party jars with UI built components in it into a titanium module project. Based on that problem specifically, I am going to resolve this ticket as 'not our bug'. This is a problem with Native Android Libraries exported as jars specifically. The underlying problem is that Native Android Library projects do not include the R classes when you export it as a jar. The reason behind this is that Android generates these files during the build process of the app (not the library). The aapt tool is used to create these files during build time. Since the aapt tool isn't used during the creation of the jar for the Native Android Library, it won't have the generated R classes in there. In native android development, the right thing to do would be to include the Native Android Library source in the same workspace and add it as a library from source. The ADT will pull in the assets accordingly and run aapt on it when the app gets built. To verify that this is not a titanium-specific bug, I've tried adding the same jar attached to the ticket, and ran it inside a native android project (without titanium). I get the same "NoClassFoundException" error since it can't find the generated R file. Then I tried to add that same library source in the build path instead of an external jar, and it worked fine (this is the approach I mentioned above). If you want ONLY your titanium module to have UI XML components, you can do this by adding the layout xml files into platform/android/res. You can reference the facebook module to see how it's done in titanium: https://github.com/appcelerator/titanium_modules/tree/master/facebook/mobile/android. Unfortunately, there is nothing we can do to support external jars with UI components on the Titanium side, since the it's a problem with the jar generation (done outside of titanium).
  16. Mark Mokryn 2013-11-15

  17. Sasa Skevin 2013-11-15

    Allen, we have a use case where adding Native Android Library source is not an option. It is a commercial product which is distributed as a binary. How to support such case?
  18. Perminder Singh Bhatia 2013-11-15

    Allen - The only reason this ticket is in Jira is the reason to support third party libraries and why would any Titanium developer take a pain to build UI in module when he can do the same in Titanium (Sorry to remind bad common sense). This is a pure Titanium Bug and if you are not able to solve it then assign it to someone else which may be to Jeff in this case.
  19. Martin Guillon 2013-11-15

    Guys it s almost here, if not already ;) https://github.com/appcelerator/titanium_mobile/pull/4935
  20. Mark Mokryn 2013-11-15

    Martin - if it's almost done, then the "real" PR for Titanium Mobile should include the latest ActionBarCompat, no? It's just the infrastructure that's the problem - the code changes should be next to trivial. What do you think? BTW ActionBarSherlock is pretty much dead as I understand it. See the differences here: http://android-developers.blogspot.co.il/2013/08/actionbarcompat-and-io-2013-app-source.html
  21. Martin Guillon 2013-11-15

    Mark i was talking about the ability to do it, which is the subject of that ticket. Now as for the implementation i already have ActionBarSherlock fully working in my public branch. You can use it. I have tried ActionBarCompat and it s really buggy.
  22. Allen Yeung 2013-12-17

  23. Mark Mokryn 2013-12-17

    Hi Allen, The problem is one that you mentioned earlier: lots of Android library projects use the R class built from the lib's XML resources. Facebook is one example, ActionBarCompat is another, etc. But taking a step back, and looking at it from a higher level: in order for Titanium to be agile and competitive in the long run, it must match the ease of integration of libraries in the same fashion as standard Android projects. Hypothetical example: Titanium's Facebook module is based on Facebook SDK p.q.r. Assume Facebook releases a version fixing critical bugs, p.q.s In the native Android case, the new version is just dropped into the project, zero coding effort after the initial integration of p.q.r. In Titanium's case - this is a huge pain since now the new Facebook *SDK* (i.e. not the module code itself) has to be hacked up in order to fit the module architecture - just see how many hacks specifically due to this exist in the Facebook SDK in your current Facebook module. This is why the Ti Facebook module is outdated, buggy, and totally underfeatured. Sorry to rant on this, but it's reality. You may see the same issue with ActionBarCompat - if you can't easily drop in new versions with bug fixes, you will very soon wind up with a stale and buggy implementation, since no one can afford to hack up Google's libraries with every version release. By hook or by crook, you have to make Android library projects be as easily usable under Titanium as they are under Android.
  24. Martin Guillon 2013-12-18

    @Allen: i agree completely. PLus it is already doable from the sdk and from plugins! see [there](https://github.com/appcelerator/titanium_mobile/pull/4935) ActionBarSherlock already in my public branch https://github.com/Akylas/titanium_mobile
  25. Mark Mokryn 2013-12-18

    So if this process works, why is it not simply thoroughly documented and already a part of 3.2.0? I admit I'm confused....
  26. Martin Guillon 2013-12-18

    @Mark: If you read the comments in the PR, you'll see that it is part of the new CLI which allows you add more hooks to the build system. It s pretty early as CLI 3.2.0 is still very young. And sometimes you have to go beyond documentation ;)
  27. Mark Mokryn 2014-02-04

    BTW, note the following: https://developers.google.com/cast/docs/android_sender Requires the appcompat library (Action Bar compatibility) along with other libs And Note: Since the libraries contribute resources, you cannot simply satisfy the dependencies by including their JAR files; instead you need to import them as library projects for your IDE.
  28. Martin Guillon 2014-02-04

    @Mark: you mix up 2 things here. - introducing libraries which have resources dependencies: ALREADY DOABLE - adding ActionBarSherlock/ActionBarCompat support: needs Ti support Integrating appcompat to create for example a GoogleCast module is already doable with the latest CLI (sdk >=3.20). Follow the links i posted to see hints on how to do it. It s really easy in fact
  29. Mark Mokryn 2014-02-04

    Hi Martin, If doable then why is this item pushed out to 3.3.0? For docs? BTW - Google Cast requires appcompat according to Google's docs, so not sure if it is indeed currently possible.
  30. Martin Guillon 2014-02-04

    What are you talking about? CLI wasn't pushed out. I don't think there is a doc for CLI though. Remember it's an open source project though ;) And BTW i just wrote il my last comment that you CAN use appcompat already. The tough point is not related to what you want but to the integration of Actionbarsherlock/ActionBarCompat into Ti Read carefully https://github.com/appcelerator/titanium_mobile/pull/4935
  31. Jose Angel Rufino Baquero 2014-02-28

  32. Vishal Duggal 2014-04-15

    All this requires is a way for developers to specify and package names they would like a R.java to be generated and the CLI honoring the request
  33. Vishal Duggal 2014-04-15

    Pull pending against master https://github.com/appcelerator/titanium_mobile/pull/5611 To generate a R.java for a specific package name add the following entry to the manifest file
        respackage: com.example.mypackage
        
  34. Vishal Duggal 2014-04-16

    Testing instructions The test can be performed with any android module Module build system Positive Test - A valid respackageinfo file is generated and zipped along with the module zip. Take any android module and add an entry to the manifest as shown above. Build the module (ant dist). Unzip the generated zip file and check to see a file respackageinfo exists in the module root(modules/android///respackageinfo). Contents of the file must be the value defined in the manifest. Negative Test - Leave the entry out and ensure that the unzipped module root has no file named respackageinfo CLI Take any android module that you app is using. Create a respackageinfo file in the module root with contents set to a valid package name. Build app for android See the build/android/gen folder. A R.java file must exist at the path specified by the package name. Check the CLI output. The aapt command must include --extra-packages
  35. Mark Mokryn 2014-04-16

    Awesome - can this be added and explained in the Android module documentation? Thanks!
  36. Unknown 2014-04-21

    This issue was previously scheduled to be worked on in more than one sprint: * 'Release 3.1.2' (on board '3.1.X Triage') * 'Release 3.3.0' (on board '3.2.X Triage') Starting from JIRA Agile 6.3, an issue can only belong to a single future sprint. Read more about this change: http://docs.atlassian.com/agile/docs-0630/Sprint+Marker+Migration This issue is now scheduled for future sprint 'Release 3.1.2' (on board '3.1.X Triage'). If this is incorrect, please update the issue accordingly. This comment was automatically generated by JIRA. If it is no longer relevant, please feel free to delete it.
  37. Martin Guillon 2014-04-23

    I have tested that PR and i confirm that it works great! Amazing work. The only thing i find quite weird is for the "respackage" key to be in the manifest. To me it should be in the build.properties
  38. Vishal Duggal 2014-04-23

    @[~farfromrefuge] The manifest is a property file. The decision to stick it into the manifest instead of build.properties was based on the following criteria 1. We have a built in object that reads in the manifest as a property. 2. This property was more about the packaging of the module rather than the building of it.
  39. Martin Guillon 2014-04-23

    @Visual Duggal I get the number 1, but no the number 2. In a sense your module "doesn't" build as any app that would use it wouldn't build :P Thanks for taking the time to answer An again great job, it works great.
  40. Mark Mokryn 2014-05-14

    @Vishal Duggal : I tried the respackage method, and it seems to only work for one library with resources, and projects often require several (e.g. for Chromecast we need Chromecast Companion Library, mediarouter library, Google Play Services, etc.). Can you please check this functionality? Thanks.
  41. Mark Mokryn 2014-05-14

    @Martin Guillon: And the CLI hook method won't work either for multiple libs with resources, at least not in the examples I saw. The reason is that the --extra-packages parameter can be used just once with aapt, and not per package. You're supposed to separate the package names with : following it. The problem then is that you need to specify the resource directories with -S, but aapt will always just use the first one, so this solution doesn't work. Any ideas?
  42. Martin Guillon 2014-05-14

    respackage only seems to support one for now. AS for my hook, the implementation of respackage actually broke it. Though it did support as many as you wanted We would need to create a new hook for it to work now. I think the best would be to make respackage support multiples res
  43. Mark Mokryn 2014-05-14

    Both the respackage and hook solutions relied on aapt's -S option to specify the res directory locations. The problem is that aapt just uses the first directory with resources it finds. So after a bit of hacking I got 3 libs to build - but they all had the same R.java file :( I'm not even sure it works reliably with one library, since I see -S twice on the aapt command line, and that could be dangerous. I'm not familiar enough with aapt, but the --extra-packages specifying multiple packages, with multiple -S definitions, definitely seems the wrong approach. Perhaps we need to run aapt separately on each external library, specifying only one res directory? It's really very frustrating that after all this time, we don't have a solid solution to this issue. I'm really hoping someone steps up and solves this once and for all.
  44. Mark Mokryn 2014-05-14

    @Vishal: for the respackageinfo - how do you determine the path to the library's res folder?
  45. Mark Mokryn 2014-05-14

    Here's a hook that should work on 3.3.0, for multiple libraries with resources. Would be nice if Appcelerator can "sanction" this so it doesn't break sometime soon with another commit.
        exports.cliVersion = '>=3.X';
        
        exports.init = function (logger, config, cli, appc) {
            cli.on('build.android.aapt', {
                pre: function(data, next) {
                    var args = data.args[1];
                    if (args.indexOf('--auto-add-overlay') < 0) {
                    	args.push('--auto-add-overlay');
                    }
                    
                    var externalLibraries = [
                        {
                            javaClass:'com.google.android.gms',
                            resPath:'/any/path/to/android-sdk-macosx/extras/google/google_play_services/libproject/google-play-services_lib/res'
                        },
                        {
                            javaClass:'android.support.v7.mediarouter',
                            resPath:'/some/path/to/android/support/v7/mediarouter/res'             	
                        }
                    ];
        
        			// --extra-packages can be defined just once
        			if (args.indexOf('--extra-packages') < 0) {
        				args.push('--extra-packages');
        				args.push('');
        			}
        			var namespaceIndex = args.indexOf('--extra-packages') + 1;
        			
        			externalLibraries.forEach(function(lib) {
        				if (args[namespaceIndex].indexOf(lib.javaClass) < 0){
        					args[namespaceIndex].length && (args[namespaceIndex] += ':');	
        					args[namespaceIndex] += lib.javaClass;
        				}
        				if (args.indexOf(lib.resPath) < 0) {
        					args.push('-S');
        					args.push(lib.resPath);
        				}
        			});
                    next(null, data);
                }
            });
        };
        
        
  46. Chris Barber 2014-05-14

    [~mokesmokes] I thankfully do not see the CLI plugin contract changing again anytime soon. :) Your hook above looks fine, though it will only work in 3.2.1 and newer. If you care about 3.2.0, then to make it work, you need to change the last line from:
        next(null, data);
        
    to
        appc.version.eq(cli.version, '3.2.0') ? next(data) : next(null, data);
        
    The "build.android.aapt" was introduced in 3.2.0, so no need to work about pre-3.2.0. Also, it's a good idea to also export an "id" and "version". I added checks in the CLI so that two versions of the same hook are not loaded which would mostly like cause issues.
        exports.id = "com.whatever.myhook";
        exports.version = "1.0";
        
  47. Mark Mokryn 2014-05-15

    I still think we need a respackage-like solution since it will be hard to distribute modules and require people to install hooks. The respackage should so something similar to the hook. I think the respackage file should look like:
        com.example.class1, /path/to/his/res
        com.example.class2, /some/other/path/to/res
        
    The classes should be uniquely added to --extra-packages, and as in the hook a -S /some/path if the path is not already included. The path names should support both absolute paths which is good for development (e.g. you want to reference a res folder that is updated by the Android SDK Manager), but it should also allow relative path to the module root folder so that we can distribute fully self contained modules. Frankly I think the bit in the manifest is superfluous - the respackageinfo is just a text file and can live in the module root, no difference between that and putting these lines manually in the manifest file.
  48. Mark Mokryn 2014-05-15

    Oh, and please change the status of this issue to open, pending the issues noted.
  49. Martin Guillon 2014-05-17

    @Mark: I totally agree on the respackageinfo file. And that s the format to go for i think. And i actually now need multiple ones too :D
  50. Mark Mokryn 2014-05-17

    @Martin: for now use the hook above, it works for me.
  51. Vishal Duggal 2014-05-21

    The current Android module structure only supports a single directory for module resources (/android/platform/android/res). We have created a ticket to add support for multiple resource directories. Please track TIMOB-17009. We will try and get it into Release 3.3.1
  52. Lokesh Choudhary 2014-06-17

    Verified the fix by following the test steps by [~vduggal] & I see a valid respackageinfo file is generated and zipped along with the module zip. Closing. Environment: Appc Studio : 3.3.0.201406111952 Ti SDK : 3.3.0.v20140616174113 Mac OSX : 10.8.5 Alloy : 1.4.0-rc CLI - 3.3.0-rc Code Processor: 1.1.1
  53. Andrey Tkachenko 2016-02-09

    How to make to work two or more jar library. Both has resources and referenced to it.
  54. David Vermeir 2016-06-17

    Is this respackageinfo solution documented somewhere?

JSON Source