- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我们希望克服的基本问题是通过 USB 将数据从充当主机和电源的外部源 (PC) 传输到 Android 设备。由于 PC 将能够供电,并使产品的最终消费者更容易使用,我们希望避免使用 OTG 电缆,因此在配件模式下运行 android 设备。
我已经设法让安卓设备进入配件模式,并识别出有一个 USB 主机连接到它,甚至能够读取主机的控制数据。但是我似乎无法弄清楚实际的批量数据传输。
除了简单地设置初始连接之外,官方 android 文档似乎对这个主题提供的内容很少。
我已经从涉及该主题的几个来源(主要来自 here)中尽可能多地在线获取代码。 , 还有其他地方。
在 Android 代码中,usbThread 启动,甚至可以访问配件并正确打印出其制造商、型号等。但是,从 inputStream 读取总是会导致 IOError。
在主机 PC 上的 C++ 代码中,一切运行顺利并连接起来,直到传输测试,其中第一个批量传输超时并且报告传输了零字节。
我总是在运行我的 C++ 代码之前终止 ADB。 android 文档说要发送一个 set_configuration(1),我试过了但没有用。他们还谈到 ADB 有第二个接口(interface),我在输出中没有看到。我确实看到了另一种接口(interface)配置,但设置和使用它根本不起作用。
是否需要任何额外的设置?我是否缺少一些基本的 USB 协议(protocol)? Android 代码是否应该简单地对 inputStream 进行连续轮询?今天这个时代还支持配件模式吗?
相关代码如下所示
主 Activity .java
//<company> contains actual reversed Internet domain name
private static final String ACTION_USB_PERMISSION = "<company>.USB_PERMISSION";
UsbManager usbManager;
usbThread thread;
boolean usbStarted = false;
boolean resumeRan = false;
boolean threadCreated = false;
UsbAccessory accessory;
ParcelFileDescriptor fileDescriptor;
FileInputStream inputStream;
FileOutputStream outputStream;
private void openAccessory() {
Log.d(TAG, "openAccessory: " + accessory);
fileDescriptor = usbManager.openAccessory(accessory);
if (fileDescriptor != null)
{
usbStarted = true;
FileDescriptor fd = fileDescriptor.getFileDescriptor();
inputStream = new FileInputStream(fd);
outputStream = new FileOutputStream(fd);
thread = new usbThread();
thread.start();
}
}
private final BroadcastReceiver permissionReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action))
{
Log.d(TAG, "Asking for usb permission");
synchronized (this)
{
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
if((!usbStarted) && resumeRan)
{
resumeRan = false;
Log.d(TAG, "Model: " + accessory.getModel());
openAccessory();
}
}
else
{
Log.d(TAG, "permission denied for device ");
}
}
}
}
};
Handler usbHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
byte res = msg.getData().getByte("val");
Log.d(TAG, "Byte " + Byte.toString(res));
}
};
private class usbThread extends Thread
{
boolean bueno = true;
usbThread()
{
if(!threadCreated)
{
threadCreated = true;
}
else
{
bueno = false;
Log.d(TAG, "Tried to open second thread");
}
}
public void run()
{
while(usbStarted && bueno)
{
byte[] buffer = new byte[10];
int ret = 0;
try
{
int av = inputStream.available();
ret = inputStream.read(buffer, 0, av);
} catch (IOException e)
{
e.printStackTrace();
//Log.d("MMI_IO_READ", "IOException on buffer read.");
}
if(ret > 0)
{
//Log.d("MMI_IO_READ", "Ret = " +ret);
for(int i = 0; i < ret; i++)
{
Message m = usbHandler.obtainMessage();
Bundle b = new Bundle();
b.putByte("val", buffer[i]);
m.setData(b);
usbHandler.sendMessage(m);
}
}
}
Log.d(TAG, "Thread Shutdown");
}
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mUsbDetachReceiver , filter);
filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(permissionReceiver, filter);
}
@Override
protected void onResume()
{
super.onResume();
UsbAccessory[] accessoryList = usbManager.getAccessoryList();
if (accessoryList != null)
{
if(!usbStarted)
{
Log.d(TAG, "Resume, usb not started");
accessory = accessoryList[0];
Log.d(TAG, "Manufacturer " + accessory.getManufacturer());
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(ACTION_USB_PERMISSION), 0);
resumeRan = true;
usbManager.requestPermission(accessory, mPermissionIntent);
}
}
}
请注意,正如 this thread 所建议的那样除其他外,以及我自己的经验,USB_ACCESSORY_ATTACH Intent 永远不会触发。因此,USB 检测依赖于不稳定的 onResume 检查。
主机USB.cpp
#include <stdio.h>
#include <libusb-1.0/libusb.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <iostream>
#define ACCESSORY_VID 0x18d1
#define ACCESSORY_PID 0x2D00
#define ACCESSORY_ADB_PID 0x2D01
#define INTERFACE 0
const char* manufacturer = "PCHost";
const char* modelName = "PCHost1";
const char* description = "Description";
const char* version = "1.0";
const char* uri = "http://example.com";
const char* serialNumber = "666";
//static
static void error(int code)
{
fprintf(stdout, "%s\n", libusb_strerror((libusb_error)code));
}
static int shutdown(libusb_device_handle *handle)
{
if(handle)
{
libusb_release_interface(handle, INTERFACE);
libusb_close(handle);
}
libusb_exit(NULL);
return 0;
}
static int init()
{
libusb_init(NULL);
libusb_set_debug(NULL, 3); //Verbose debugging level
return 0;
}
// Send AOA specified introdction control information.
static int androidIntroduction(libusb_device_handle *handle)
{
unsigned char ioBuffer[2];
int devVersion;
int response;
response = libusb_control_transfer(
handle, //handle
0xC0, //bmRequestType
51, //bRequest
0, //wValue
0, //wIndex
ioBuffer, //data
2, //wLength
100 //timeout
);
fprintf(stdout,"Sent getProtocol\n");
if(response < 0)
{error(response);return -1;}
fprintf(stdout,"Response \n");
devVersion = ioBuffer[1] << 8 | ioBuffer[0];
if(!(devVersion == 1 || devVersion==2))
return -1;
fprintf(stdout,"Version Code Device: %d\n", devVersion);
usleep(1000);//sometimes hangs on the next transfer :(
response = libusb_control_transfer(handle,0x40,52,0,0,(unsigned char*)manufacturer,strlen(manufacturer)+1,0);
if(response < 0)
{error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,1,(unsigned char*)modelName,strlen(modelName)+1,0);
if(response < 0)
{error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,2,(unsigned char*)description,strlen(description)+1,0);
if(response < 0)
{error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,3,(unsigned char*)version,strlen(version)+1,0);
if(response < 0)
{error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,4,(unsigned char*)uri,strlen(uri)+1,0);
if(response < 0)
{error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,5,(unsigned char*)serialNumber,strlen(serialNumber)+1,0);
if(response < 0)
{error(response);return -1;}
fprintf(stdout,"Accessory Identification sent\n");
return 1;
}
// Send introduction information to given handle, then try to put it into
// accessory mode and catch it once it reconnects.
static libusb_device_handle* setupAccessory(libusb_device_handle *handle)
{
int response;
response = androidIntroduction(handle);
if(response < 0)
return NULL;
response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
if(response < 0){error(response);return NULL;}
fprintf(stdout,"Attempted to put device into accessory mode\n");
libusb_device_handle *androidHandle;
int tries = 4;
while(true)
{
tries--;
if((androidHandle = libusb_open_device_with_vid_pid(NULL, ACCESSORY_VID, ACCESSORY_ADB_PID)) == NULL)
{
if((androidHandle = libusb_open_device_with_vid_pid(NULL, ACCESSORY_VID, ACCESSORY_PID)) == NULL)
{
if(tries < 0)
{
std::cout << "Could not..." << '\n';
return NULL;
}
}
else
{
break;
}
}else
{
break;
}
usleep(1000000);
}
return androidHandle;
}
//Find the first Bulk OUT Enpoint of the given device.
uint8_t findBulkOut (libusb_device *device)
{
libusb_config_descriptor *con_desc;
libusb_get_active_config_descriptor(device, &con_desc);
const libusb_interface *interfaceList = con_desc->interface;
uint16_t numInterface = con_desc->bNumInterfaces;
for(int j = 0; j<numInterface; j++)
{
libusb_interface interface = interfaceList[j];
const libusb_interface_descriptor *intDescList = interface.altsetting;
int numAlt = interface.num_altsetting;
for(int p = 0; p < numAlt; p++)
{
libusb_interface_descriptor intDesc = intDescList[p];
uint8_t numEnd = intDesc.bNumEndpoints;
const libusb_endpoint_descriptor *ends = intDesc.endpoint;
for(int k = 0; k < numEnd; k++)
{
libusb_endpoint_descriptor endpoint = ends[k];
uint8_t type = 0x03 & endpoint.bmAttributes;
uint8_t address = endpoint.bEndpointAddress;
switch (type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
break;
case LIBUSB_TRANSFER_TYPE_BULK:
if(!(address & LIBUSB_ENDPOINT_IN)) //LIBUSB_ENPOINT_OUT is simply 0000, can't AND that...
{
return address;
}
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
break;
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
break;
}
}
}
}
}
//Basically findBulkOut, but with output for EndPoints.
void printEnds (libusb_device *device)
{
libusb_config_descriptor *con_desc;
libusb_get_active_config_descriptor(device, &con_desc);
const libusb_interface *interfaceList = con_desc->interface;
uint16_t numInterface = con_desc->bNumInterfaces;
for(int j = 0; j<numInterface; j++)
{
libusb_interface interface = interfaceList[j];
const libusb_interface_descriptor *intDescList = interface.altsetting;
int numAlt = interface.num_altsetting;
for(int p = 0; p < numAlt; p++)
{
libusb_interface_descriptor intDesc = intDescList[p];
uint8_t numEnd = intDesc.bNumEndpoints;
const libusb_endpoint_descriptor *ends = intDesc.endpoint;
fprintf(stdout, "Interface %d. altSetting %d. Num of endpoints: %d\n", p, intDesc.bInterfaceNumber, numEnd);
for(int k = 0; k < numEnd; k++)
{
libusb_endpoint_descriptor endpoint = ends[k];
uint8_t type = 0x03 & endpoint.bmAttributes;
uint8_t address = endpoint.bEndpointAddress;
fprintf(stdout, "Endpoint type ");
switch (type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
std::cout << "Control";
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
std::cout << "Isochronus";
break;
case LIBUSB_TRANSFER_TYPE_BULK:
std::cout << "Bulk";
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
std::cout << "Interupt";
break;
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
std::cout << "Bulk Stream";
break;
}
std::cout << " ";
std::cout << (address & LIBUSB_ENDPOINT_IN ? "IN" : "OUT");
std::cout << '\n';
fprintf(stdout, "Address %04X\n", address);
}
}
}
}
// Go through all connected devices. If they are do not have Google PID
// and VID, try to find out if they are Android devices. If they (most likely)
// are, try to put them in accessory mode. If successful, return that handle
libusb_device_handle* getAndroidHandle()
{
libusb_device **list;
ssize_t cnt = libusb_get_device_list(NULL, &list);
ssize_t i = 0;
int err = 0;
if (cnt < 0)
error(0);
for (i = 0; i < cnt; i++)
{
fprintf(stdout,"\nAttempted index %d\n", (int)i);
libusb_device *device = list[i];
libusb_device_descriptor dev_desc;
libusb_get_device_descriptor(device, &dev_desc);
uint16_t VID = dev_desc.idVendor;
uint16_t PID = dev_desc.idProduct;
fprintf(stdout, "VID: %04X. PID: %04X\n", VID, PID);
libusb_device_handle *handle;
int response = libusb_open(device, &handle);
if(response < 0)
{error(response);continue;}
libusb_set_auto_detach_kernel_driver(handle, 1);
libusb_device_handle *androidHandle;
if(VID == ACCESSORY_VID && (PID == ACCESSORY_PID || PID == ACCESSORY_ADB_PID))
{
int r = androidIntroduction(handle);
if (r != 1)
continue;
androidHandle = handle;
}
else
{
androidHandle = setupAccessory(handle);
libusb_close(handle);
}
if (androidHandle)
{
libusb_free_device_list(list, 1);
std::cout << "\n\nAndroid Found:" << '\n';
printEnds(libusb_get_device(androidHandle));
return androidHandle;
}
}
libusb_free_device_list(list, 1);
return NULL;
}
//Try to send data.
static int transferTest(libusb_device_handle *handle)
{
const static int PACKET_BULK_LEN=64;
const static int TIMEOUT=5000;
int r,i;
int transferred;
usleep(1000000); //1s
//libusb_set_configuration(handle, 1);
r = libusb_claim_interface(handle, INTERFACE);
if(r < 0)
{error(r); return -1;}
fprintf(stdout, "Interface claimed, ready to transfer data\n");
// TEST BULK IN/OUT
usleep(100000);// 0.1s
uint8_t outAddress = findBulkOut(libusb_get_device(handle));
fprintf(stdout, "Trying to write to %04X\n", outAddress );
char answer[PACKET_BULK_LEN];
char question[PACKET_BULK_LEN];
for (i=0;i<PACKET_BULK_LEN; i++) question[i]=i;
// ***TIMES OUT HERE***
r = libusb_bulk_transfer(handle, outAddress, (unsigned char*)question, PACKET_BULK_LEN,
&transferred,TIMEOUT);
if (r < 0)
{
fprintf(stderr, "Bulk write error %d\n", r);
error(r);
fprintf(stderr, "Number of bytes written %d\n", transferred);
return r;
}
fprintf(stdout, "Wrote %d bytes", transferred);
/*r = libusb_bulk_transfer(handle, ENDPOINT_BULK_IN, (unsigned char*)answer,PACKET_BULK_LEN,
&transferred, TIMEOUT);
if (r < 0)
{
fprintf(stderr, "Bulk read error %d\n", r);
error(r);
return r;
}
fprintf(stdout, "Read %d bytes", r);
if (transferred < PACKET_BULK_LEN)
{
fprintf(stderr, "Bulk transfer short read (%d)\n", r);
error(r);
return -1;
}
printf("Bulk Transfer Loop Test Result:\n");
// for (i=0;i< PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]);
for(i = 0;i < PACKET_BULK_LEN; i++)
{
if(i%8 == 0)
printf("\n");
printf("%02x, %02x; ",question[i],answer[i]);
}
printf("\n\n");
*/return 0;
}
int main (int argc, char *argv[])
{
fprintf(stdout, "OUT flag %04X IN flag %04X\n", LIBUSB_ENDPOINT_OUT, LIBUSB_ENDPOINT_IN);
fprintf(stdout, "Shifted in %04X\n", LIBUSB_ENDPOINT_IN >> 7);
if(init() < 0)
return -1;
libusb_device_handle *handle = getAndroidHandle();
if(!handle)
{
fprintf(stdout, "\nError setting up accessory\n");
shutdown(NULL);
return -1;
};
if(transferTest(handle) < 0)
{
fprintf(stdout, "\nError in transferTest\n");
shutdown(handle);
return -1;
}
shutdown(handle);
fprintf(stdout, "\nFinished\n");
return 0;
}
提前感谢您的任何回复! :)
编辑
似乎是 inputStream.available() 是罪魁祸首,但似乎无法正常工作(我从一些随机谷歌搜索中发现)。无论设置是否正确,它都会抛出 IOException。我还取消了 libusb_set_configuration 的注释并设置了一个轻微的延迟以确保它正常工作。
旁注:我不必关闭 ADB 服务器即可使 USB 连接正常工作。如果设备以 0x2D01 作为 PID self 介绍,那么 ADB 日志记录就可以正常工作!
最佳答案
这是我的 Java 代码,也许它会对你有所帮助。
如果在 AOA 模式后添加 libusb_set_configuartion,上面的 C++ 代码也可以工作。
import android.app.PendingIntent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//import java.util.logging.Logger;
public class MainActivity extends Activity implements Runnable
{
private static final String ACTION_USB_PERMISSION = "com.examples.accessory.controller.action.USB_PERMISSION";
private final String TAG = "_ITE";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
setContentView(R.layout.activity_main);
//enableControls(false);
}
@Override
public void onResume()
{
super.onResume();
Intent intent = getIntent();
if (mInputStream != null && mOutputStream != null) {
return;
}
UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null)
{
if (mUsbManager.hasPermission(accessory))
{
openAccessory(accessory);
}
else
{
synchronized (mUsbReceiver)
{
if (!mPermissionRequestPending)
{
mUsbManager.requestPermission(accessory,mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
}
else
{
Log.d(TAG, "mAccessory is null");
}
}
@Override
public void onPause() {
super.onPause();
closeAccessory();
}
@Override
public void onDestroy() {
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
private void openAccessory(UsbAccessory accessory)
{
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryController");
thread.start();
Log.d(TAG, "accessory opened");
//enableControls(true);
} else {
Log.d(TAG, "accessory open fail");
}
}
private void closeAccessory() {
//enableControls(false);
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
}
}
/*
* This receiver monitors for the event of a user granting permission to use
* the attached accessory. If the user has checked to always allow, this will
* be generated following attachment without further user interaction.
*/
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory "+ accessory);
}
mPermissionRequestPending = false;
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null && accessory.equals(mAccessory)) {
closeAccessory();
}
}
}
};
/*
* Runnable block that will poll the accessory data stream
* for regular updates, posting each message it finds to a
* Handler. This is run on a spawned background thread.
*/
public void run() {
int ret = 0;
byte[] buffer = new byte[16384];
int i;
while (ret >= 0)
{
try
{
ret = mInputStream.read(buffer);
} catch (IOException e) {
break;
}
}
}
}
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<uses-library android:name="com.android.future.usb.accessory" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" >
</meta-data>
</activity>
</application>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-accessory model="YourModel" manufacturer="yourname" version="0.0.1"/>
</resources>
关于java - Android USB 附件模式无法使用 libusb 与主机 PC 读取/写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45420126/
我没有上传附件以使浏览器正常工作。 一些提示是 here , 其他 there . The docs非常好,但我无法将其转换为 AJAX 上传。 我正在寻找一个 super 简单的 HTML/Java
我有一个应用程序可以收集一些信息并允许用户使用 Android 的 Intent 框架共享这些信息。 到目前为止,它以纯文本形式共享报告:使用 putExtra(Intent.EXTRA_TEXT,
我正在尝试通过我的应用程序发布带有附件图片的消息,所以我使用了以下代码: function yamPost(mytoken) { var msg_Body = jQuery("#myB
我在用户表中使用了多对多关系来使登录用户关注另一个用户,但我自己没有弄清楚,我检查了其他人做了什么,并尝试做类似的事情,并且它有效。在我的方法中,我有: function follow(User $u
我正在用 PHP 创建脚本,其作用是将 IMAP 服务器备份到 MySQL 数据库。 我现在的问题是: 如果电子邮件有附件,附件是嵌入在电子邮件本身中还是服务器上的一个单独文件? 我问的原因是: 我可
我正在使用 RavenDB,在我处理任何附件之前删除了一些带有附件的测试文档,所以我在想它们是否还在磁盘上的某个地方,以及如何轻松地找到它们?。 另一个问题是:当文档被删除时,它有一个附件,附件会被自
当您使用 ACTION_SEND Intent (使用额外的 EXTRA_STREAM)将文件附加到电子邮件时,电子邮件应用程序是否将该附加文件复制到它自己的位置?我的应用程序创建了一个文件并将其附加
所以: // Setup mail class, recipients and body $mailer->AddAttachment('/home/mywebsite/public_html/fil
您好,我需要一个 DnD 解决方案来将 Outlook 邮件附件拖到 Stackpane。 JavaFX/展望 2010 stackpaneDragAndDropZone.setOnDragO
我尝试制作一个 PhpSpreadsheet 文档,然后将他添加到邮件附件中。也许是太热了,但在 phpSpreadsheet 文档中几个小时后,我还没有找到任何东西。 这是我发送邮件的文件 $nam
有什么方法可以动画删除 UITableView 单元格附件吗? 我当前正在显示一个 UITableViewCellAccessoryDisclosureIndicator,但我想在所有可见表格单元格上
我正在编写一个 iPhone 应用程序,它要求我以编程方式发送电子邮件附件。附件是我通过代码创建的 csv 文件。然后,我将文件附加到电子邮件中,附件就会显示在手机上。但是,当我向自己发送电子邮件时,
我正在尝试通过收件箱中的名称“MacroEnabled”访问子文件夹,找到其中的所有附件并将它们保存到本地驱动器。 我使用此代码创建一个名为“Documents”的文件夹并保存附件。然而,在进行第二次
将 corda 升级到版本 4 后,我收到 net.corda.core.transactions.MissingContractAttachments:找不到 com.template.contra
我正在尝试让 Jenkins 将一个或一组文件附加到作业已完成的电子邮件通知中。我不断收到以下错误: 发送电子邮件以触发:成功错误:访问要附加的文件时出错:需要 Ant GLOB 模式,但看到 C:\
我创建了一个由来自 mysql 的数据填充的 UITableView(使用 NSJSONSERIALIZATION)。现在问题是一回事。我检索到的是产品名称。我想要一个附件 View (像单元格右侧的
我开发了一个 Java 客户端应用程序,用于下载我自己的电子邮件。我发现我无法在电子邮件中找到某些附件,特别是当我向经过认证的公司发送电子邮件时收到的作为收据的 XML 文件。我用于下载附件的代码:
我正在将我的 sqlite 数据库转换为 Couchdb。我可以转换数据库并上传到 Couchdb 服务器。除了图像之外的一切。我想将图像作为独立附件上传,我想使用 javascript、REST 和
我编写了一段代码,以便能够启动默认的电子邮件服务提供商,即我的 Outlook。这是我的代码: if(role.getValue().equals("1")) { Desktop desktop =
我正在尝试使用链接上共享的代码使用 python 从 Gmail 下载电子邮件附件 https://gist.github.com/baali/2633554 我想应用时间过滤器+主题过滤器并下载附件
我是一名优秀的程序员,十分优秀!