[TIMOB-11995] Android: Duplicate setter in module causes cryptic packaging failure
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Low |
Status | Closed |
Resolution | Won't Fix |
Resolution Date | 2017-07-19T17:45:23.000+0000 |
Affected Version/s | Release 2.1.3 |
Fix Version/s | n/a |
Components | Android |
Labels | n/a |
Reporter | Arthur Evans |
Assignee | Eric Merriman |
Created | 2012-12-07T19:37:02.000+0000 |
Updated | 2017-07-19T17:45:23.000+0000 |
Description
If a proxy object defines a property using
propertyAccessors
and also defines a custom setter for the property, build fails with the following cryptic (and completely misleading) message:
Executing build.xml...
/Library/Application Support/Titanium/mobilesdk/osx/2.1.4.GA/module/android/build.xml:191: The following error occurred while executing this line:
/Library/Application Support/Titanium/mobilesdk/osx/2.1.4.GA/module/android/build.xml:236: The following error occurred while executing this line:
/Library/Application Support/Titanium/mobilesdk/osx/2.1.4.GA/module/android/build.xml:240: The following error occurred while executing this line:
/Library/Application Support/Titanium/mobilesdk/osx/2.1.4.GA/module/android/build.xml:221: Java returned: -1You may need to install the Command Line Tools package through XCode, in case you haven't done so yet.
Sample code follows:
/**
* This file was auto-generated by the Titanium Module SDK helper for Android
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
*/
package com.evarino.actionbarsearch;
import java.util.HashMap;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.Log;
import org.appcelerator.titanium.util.TiConfig;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiCompositeLayout;
import org.appcelerator.titanium.view.TiCompositeLayout.LayoutArrangement;
import org.appcelerator.titanium.view.TiUIView;
import android.app.Activity;
import android.os.Build;
import android.widget.SearchView;
// This proxy can be created by calling Actionbarsearch.createExample({message: "hello world"})
@Kroll.proxy(creatableInModule = ActionbarsearchModule.class, propertyAccessors = {
"prompt", "hintText", "showCancel", "value" })
public class ABSearchViewProxy extends TiViewProxy {
// Standard Debugging variables
private static final String LCAT = "SearchProxy";
private static final boolean DBG = TiConfig.LOGD;
// property names
private static final String HINT_TEXT = "hintText";
private static final String VALUE = "value";
private static final String ICONIFIED = "iconified";
private static final String ICONIFIED_BY_DEFAULT = "iconifiedByDefault";
// Event names -- matched to SearchBar for consistency -- except "submit", which is android-specific.
private static final String TEXT_CHANGE_EVENT = "change";
private static final String TEXT_SUBMIT_EVENT = "submit";
private static final String CLOSE_EVENT = "cancel";
private class ABSearchView extends TiUIView implements SearchView.OnQueryTextListener, SearchView.OnCloseListener {
private SearchView searchView;
public ABSearchView(TiViewProxy proxy) {
super(proxy);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
searchView = new SearchView(proxy.getActivity());
searchView.setOnQueryTextListener(this);
searchView.setOnCloseListener(this);
setNativeView(searchView);
}
}
@Override
public void processProperties(KrollDict props) {
super.processProperties(props);
Log.d(LCAT,"[VIEW LIFECYCLE EVENT] processProperties " + props);
// Check if the hint text is specified when the view is created.
if (props.containsKey(HINT_TEXT)) {
searchView.setQueryHint(props.getString(HINT_TEXT));
}
if (props.containsKey(VALUE)) {
searchView.setQuery(props.getString(VALUE), false);
}
if (props.containsKey(ICONIFIED)) {
searchView.setIconified(props.getBoolean(ICONIFIED));
}
if (props.containsKey(ICONIFIED_BY_DEFAULT)) {
searchView.setIconified(props.getBoolean(ICONIFIED_BY_DEFAULT));
}
}
@Override
public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy) {
Log.d(LCAT, "Got change event for: " + key);
if (key.equals(HINT_TEXT)) {
searchView.setQueryHint((String) newValue);
} else if (key.equals(VALUE)) {
searchView.setQuery((String) newValue, false);
}
else if (key.equals(ICONIFIED)) {
searchView.setIconified(TiConvert.toBoolean(newValue));
} else if (key.equals(ICONIFIED_BY_DEFAULT)) {
searchView.setIconified(TiConvert.toBoolean(newValue));
}
}
@Override
public boolean onClose() {
if (proxy.hasListeners(CLOSE_EVENT)) {
proxy.fireEvent(CLOSE_EVENT, null);
return true;
} else {
return false;
} }
@Override
public boolean onQueryTextChange(String query) {
// It is a good idea to check if there are listeners for the event that
// is about to be fired. There could be zero or multiple listeners for the
// specified event.
proxy.setProperty(VALUE, query);
if (proxy.hasListeners(TEXT_CHANGE_EVENT)) {
proxy.fireEvent(TEXT_CHANGE_EVENT, null);
return true;
} else {
return false;
}
}
@Override
public boolean onQueryTextSubmit(String query) {
if (proxy.hasListeners(TEXT_SUBMIT_EVENT)) {
proxy.fireEvent(TEXT_SUBMIT_EVENT, null);
return true;
} else {
return false;
}
}
}
// Constructor
public ABSearchViewProxy() {
super();
}
@Override
public TiUIView createView(Activity activity) {
TiUIView view = new ABSearchView(this);
view.getLayoutParams().autoFillsHeight = true;
view.getLayoutParams().autoFillsWidth = true;
return view;
}
// Handle creation options
@Override
public void handleCreationDict(KrollDict options) {
super.handleCreationDict(options);
if (options.containsKey("message")) {
Log.d(LCAT,
"example created with message: " + options.get("message"));
}
}
// Methods
@Kroll.method
public void printMessage(String message) {
Log.d(LCAT, "printing message: " + message);
}
@Kroll.getProperty
@Kroll.method
public String getMessage() {
return (String) getProperty("message");
}
@Kroll.setProperty(retain=true)
@Kroll.method
public void setMessage(String message) {
Log.d(LCAT, "Tried setting module message to: " + message);
//setPropertyAndFire("message", message);
}
@Kroll.setProperty
@Kroll.method
public void setHintText(String text) {
Log.d(LCAT, "Tried setting module message to: " + text);
//setProperty("hintText", text);
}
}
After commenting out the setHintText
method and removing the build directory, the module builds fine.
Since a similar pattern works on iOS, people are likely to expect it will work on Android.
I will document it, but it would be good if we could provide a better error message, as well.
It appears that the failure is in the rhino.idswitch code, which isn't ours. Perhaps we can just fix the Ant buildfile to give a better message when this script fails, indicating that it could be because of a duplicate identifier OR missing Xcode tools.
Closing ticket due to time passed and lack of progress for a number of years. Please open a new ticket if there are any problems.