Статьи

Android: передача файлов с помощью asmack и Openfire

Я видел, как многие люди боролись с передачей файлов в asmackсреде сборки Android и исправлениях для smack . Я попробовал ту же библиотеку с сервером Openfire после некоторой отладки. Поэтому я хотел бы поделиться своей проблемой и решением для нее. Я обнаружил, что проблема в хосте Byte Stream, он пытается подключиться к неправильному хосту для инициации передачи файлов с использованием потоков байтов. Если вы не настроили прокси-сервер для передачи файлов должным образом, он выберет 127.0.0.1 или localhost или любой внутренне настроенный хост / ip в качестве хоста bytestream, который в android не считается надлежащим ip для связи. Но подождите, почему он работает правильно с настольным клиентом на том же сервере. Причина в том, что настольные клиенты могут легко идентифицировать этот ips и использовать его для открытия сокета для передачи файлов.

Имена переменных, используемые в следующих обсуждениях:

название Смысл
MyHost Имя хоста машины, на которой работает Openfire.
user1 @ MyHost Пользователь инициатора передачи файлов
user2 @ MyHost Получатель файла

Как узнать, какой хост выбран для байтовых потоков: (Следующие XML-файлы показаны по мере их отправки и получения инициатору передачи файлов.)

  • Сначала запросите у другого клиента информацию о поддерживаемых функциях:

Отправлено:

1
2
3
<iq id='x1ixz-13' to='user2@myHost/Smack' type='get'>
   <query xmlns='http://jabber.org/protocol/disco#info'></query>
</iq>

Получено:

1
2
3
4
5
6
7
<iq id='x1ixz-13' to='user1@myHost/Smack' type='result' from='user2@myHost/Smack'>
      <!—some other items -->
      <feature var='http://jabber.org/protocol/bytestreams'/>
      <!—some other items -->
   </query>
</iq>

Здесь вы можете узнать, поддерживается ли передача файла bytestream на стороне клиента или нет. Если в ответ вы видите XML-код, подобный приведенному выше, он поддерживается на другой стороне, и вы можете пойти дальше.

  • Сервер запросов для элементов диско:

Отправлено:

1
2
3
<iq id='x1ixz-14' to='myHost' type='get'>
   <query xmlns='http://jabber.org/protocol/disco#items'></query>
</iq>

Получено:

1
2
3
4
5
6
7
<iq type='result' id='x1ixz-14' from='myHost' to='user1@ myHost /Smack'>
      <!—some other items -->
      <item jid='proxy. myHost ' name='Socks 5 Bytestreams Proxy'/>
      <!—some other items -->
   </query>
</iq>

Здесь вы получите различные элементы для различных элементов, поддерживаемых сервером, например, прокси для передачи файлов, службы поиска, конференц-службы … Элемент, который мы должны искать, это «Socks 5 Bytestreams Proxy».

  • Запрос дополнительной информации о прокси

Отправлено:

1
2
3
<iq id='x1ixz-19' to='proxy. myHost ' type='get'>
</iq>

Получено:

1
2
3
4
5
<iq type='result' id='x1ixz-19' from='proxy. myHost '  to='user1@ myHost /Smack'>
      <streamhost jid='proxy. myHost ' host=' myHost ' port='7777'/>
   </query>
</iq>

Здесь хост в <streamhost> является ключом для передачи файла. Вы должны убедиться, что этот хост доступен с вашего телефона Android. Он не должен быть похож на localhost, 127.0.0.1 или какой-либо другой внутренний сервер компании, который недоступен за пределами компании. Это должен быть общедоступный IP-адрес или хост.

Чтобы настроить соответствующий прокси, добавьте / измените эти 3 свойства в Openfire:

  1. xmpp.proxy.enabled — правда
  2. xmpp.proxy.port — 7777
  3. xmpp.proxy.externalip — [общедоступный хост или ip]

Код для передачи файлов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FileTransferManager manager = new FileTransferManager(connection);
OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer('usre2@myHost/Smack');
File file = new File(filenameWithPath);
try {
   transfer.sendFile(file, 'test_file');
} catch (XMPPException e) {
   e.printStackTrace();
}
while(!transfer.isDone()) {
   if(transfer.getStatus().equals(Status.error)) {
      System.out.println('ERROR!!! ' + transfer.getError());
   } else if (transfer.getStatus().equals(Status.cancelled)
                    || transfer.getStatus().equals(Status.refused)) {
      System.out.println('Cancelled!!! ' + transfer.getError());
   }
   try {
      Thread.sleep(1000L);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}
if(transfer.getStatus().equals(Status.refused) || transfer.getStatus().equals(Status.error)
 || transfer.getStatus().equals(Status.cancelled)){
   System.out.println('refused cancelled error ' + transfer.getError());
} else {
   System.out.println('Success');
}

И код для файла получают:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
FileTransferManager manager = new FileTransferManager(connection);
manager.addFileTransferListener(new FileTransferListener() {
   public void fileTransferRequest(final FileTransferRequest request) {
      new Thread(){
         @Override
         public void run() {
            IncomingFileTransfer transfer = request.accept();
            File mf = Environment.getExternalStorageDirectory();
            File file = new File(mf.getAbsoluteFile()+'/DCIM/Camera/' + transfer.getFileName());
            try{
                transfer.recieveFile(file);
                while(!transfer.isDone()) {
                   try{
                      Thread.sleep(1000L);
                   }catch (Exception e) {
                      Log.e('', e.getMessage());
                   }
                   if(transfer.getStatus().equals(Status.error)) {
                      Log.e('ERROR!!! ', transfer.getError() + '');
                   }
                   if(transfer.getException() != null) {
                      transfer.getException().printStackTrace();
                   }
                }
             }catch (Exception e) {
                Log.e('', e.getMessage());
            }
         };
       }.start();
    }
 });

Также сконфигурируйте ProviderManager для правильного декодирования / разбора байтов и других необходимых xmls:

1
2
3
ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/bytestreams', new BytestreamsProvider());
ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/disco#items', new DiscoverItemsProvider());
ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/disco#info', new DiscoverInfoProvider());

Я использовал библиотеку asmack asmack-jse-buddycloud.jar.

Ссылка: передача файлов в Android с Asmack и Openfire от нашего партнера JCG Харш Равал в блоге harryjoy .