getSearchForm devuelve nulo cuando se usa UserSearch en XMPP con aSmack

Tengo este código, casi sin modificaciones de ejemplos:

UserSearchManager usm = new UserSearchManager(conn); Form searchForm = usm.getSearchForm("search.myserver.com"); Form answerForm = searchForm.createAnswerForm(); answerForm.setAnswer("Username", true); answerForm.setAnswer("search", contact.getJid()); ReportedData data = usm.getSearchResults(answerForm, "search.myserver.com"); 

Esto funciona perfectamente en un entorno de escritorio, usando la librería Smack, pero no puedo hacerlo funcionar en Android (donde tengo que usar asmack).

El problema es que searchForm es nulo porque getSearchForm devuelve null. Esto parece ser bastante extraño ya que no puedo encontrar ninguna documentación sobre qué casos ese método debería devolver nulo.

El servidor es Openfire, si ayuda.

Actualización 04/2014

La respuesta original a continuación contiene información antigua y obsoleta. Desde aSmack 0.8 ya no es necesario configurar manualmente el administrador de proveedores. Llamar a SmackAndroid.init(Context) como aSmack README le dice que haga, se encarga de todas las inicializaciones necesarias.

Respuesta original

Al final, el problema fue global para todos los asmack. Parece que es un problema conocido: el archivo smack.providers, normalmente en la carpeta / META-INF en versiones normales de smack, no se puede cargar en Android porque está empaquetado en el contenedor. Por lo tanto, todos los proveedores deben inicializarse a mano, como se muestra en la respuesta de Mike Ryan en este hilo: http://community.igniterealtime.org/message/201866#201866

Eliminé las cosas que no funcionaron para mí, y este es el resultado.

 public void configure(ProviderManager pm) { // Private Data Storage pm.addIQProvider("query","jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider()); // Time try { pm.addIQProvider("query","jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time")); } catch (ClassNotFoundException e) { Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time"); } // Roster Exchange pm.addExtensionProvider("x","jabber:x:roster", new RosterExchangeProvider()); // Message Events pm.addExtensionProvider("x","jabber:x:event", new MessageEventProvider()); // Chat State pm.addExtensionProvider("active","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); // XHTML pm.addExtensionProvider("html","http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider()); // Group Chat Invitations pm.addExtensionProvider("x","jabber:x:conference", new GroupChatInvitation.Provider()); // Service Discovery # Items pm.addIQProvider("query","http://jabber.org/protocol/disco#items", new DiscoverItemsProvider()); // Service Discovery # Info pm.addIQProvider("query","http://jabber.org/protocol/disco#info", new DiscoverInfoProvider()); // Data Forms pm.addExtensionProvider("x","jabber:x:data", new DataFormProvider()); // MUC User pm.addExtensionProvider("x","http://jabber.org/protocol/muc#user", new MUCUserProvider()); // MUC Admin pm.addIQProvider("query","http://jabber.org/protocol/muc#admin", new MUCAdminProvider()); // MUC Owner pm.addIQProvider("query","http://jabber.org/protocol/muc#owner", new MUCOwnerProvider()); // Delayed Delivery pm.addExtensionProvider("x","jabber:x:delay", new DelayInformationProvider()); // Version try { pm.addIQProvider("query","jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version")); } catch (ClassNotFoundException e) { // Not sure what's happening here. } // VCard pm.addIQProvider("vCard","vcard-temp", new VCardProvider()); // Offline Message Requests pm.addIQProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider()); // Offline Message Indicator pm.addExtensionProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider()); // Last Activity pm.addIQProvider("query","jabber:iq:last", new LastActivity.Provider()); // User Search pm.addIQProvider("query","jabber:iq:search", new UserSearch.Provider()); // SharedGroupsInfo pm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider()); // JEP-33: Extended Stanza Addressing pm.addExtensionProvider("addresses","http://jabber.org/protocol/address", new MultipleAddressesProvider()); // FileTransfer pm.addIQProvider("si","http://jabber.org/protocol/si", new StreamInitiationProvider()); pm.addIQProvider("query","http://jabber.org/protocol/bytestreams", new BytestreamsProvider()); // Privacy pm.addIQProvider("query","jabber:iq:privacy", new PrivacyProvider()); pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider()); pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError()); pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError()); pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError()); pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError()); pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError()); 

}

Solo comenté un par de líneas, y voilà. Se debe invocar esto antes de crear una instancia de XMPPConnection, con una línea como esta:

  configure(ProviderManager.getInstance()); 

Ahora tendré que lidiar con mis otros problemas, pero al menos este se resuelve 🙂

En el ejemplo de código XmppTool.java , getSearchFrom se usa en searchUsers() .

 public List searchUsers(String serverDomain,String userName){ List list = new ArrayList(); UserSearchManager userSearchManager = new UserSearchManager(con); try { Form searchForm = userSearchManager.getSearchForm("search."+serverDomain); Form answerForm = searchForm.createAnswerForm(); answerForm.setAnswer("Username", true); answerForm.setAnswer("Name", true); answerForm.setAnswer("search", userName); ReportedData data = userSearchManager.getSearchResults(answerForm, "search."+serverDomain); Iterator rows = data.getRows(); while(rows.hasNext()){ User user = new User(); Row row = rows.next(); user.setUserName(row.getValues("Username").next().toString()); user.setName(row.getValues("Name").next().toString()); SLog.i(tag, user.toString()); list.add(user); } } catch (XMPPException e) { SLog.e(tag, Log.getStackTraceString(e)); } return list; } 

Puede consultar la configuración global en el archivo java para reparar su código.

El Javadoc de UserSearchManager lo explica de la siguiente manera:

El UserSearchManager es una fachada construida sobre Jabber Search Services (JEP-055) para permitir la búsqueda de repositorys en un servidor Jabber. Esta implementación permite la transparencia de la implementación de la búsqueda (DataForms o No DataForms), pero permite al usuario simplemente usar el modelo DataForm para ambos tipos de soporte.

  XMPPConnection con = new XMPPConnection("jabber.org"); con.login("john", "doe"); UserSearchManager search = new UserSearchManager(con, "users.jabber.org"); Form searchForm = search.getSearchForm(); Form answerForm = searchForm.createAnswerForm(); answerForm.setAnswer("last", "DeMoro"); ReportedData data = search.getSearchResults(answerForm); // Use Returned Data