Enviar y recibir imágenes
Product deprecation notice
Effective April 30th, 2026, Vonage In-App Messaging will no longer be available. Access for new users will be closed, and the service will be discontinued for all existing users.
If you have any questions regarding this product’s discontinuation, please contact your account manager or our support team.
Visión general
Esta guía cubre el envío y recepción de imágenes dentro de una conversación.
Antes de empezar, asegúrese de que ha añadido el SDK a su aplicación y eres capaz de crear una conversación.
NOTA: Hay disponible un tutorial paso a paso para crear una aplicación de chat aquí.
Esta guía hará uso de los siguientes conceptos:
- Eventos de conversación -
messageeventos que se disparan en una Conversación, después de ser Miembro
Enviar una imagen
Dada una conversación de la que ya eres miembro:
// Scenario #1: Send an image from a URL
conversation.sendMessage({
"message_type": "image",
"image": {
"url": "https://example.com/image.jpg"
}
}).then((event) => {
console.log("message was sent", event);
}).catch((error)=>{
console.error("error sending the message", error);
});
// Scenario #2: Upload an image from a file input to Vonage, then send
// Note: the URL will need to be downloaded using the fetch image method mentioned in the next section.
const fileInput = document.getElementById('fileInput');
const params = {
quality_ratio : "90",
medium_size_ratio: "40",
thumbnail_size_ratio: "20"
}
conversation.uploadImage(fileInput.files[0], params).then((imageRequest) => {
imageRequest.onreadystatechange = () => {
if (imageRequest.readyState === 4 && imageRequest.status === 200) {
try {
const { original, medium, thumbnail } = JSON.parse(imageRequest.responseText);
const message = {
message_type: 'image',
image: {
url: original.url ?? medium.url ?? thumbnail.url
}
}
return conversation.sendMessage(message);
} catch (error) {
console.error("error sending the image", error);
}
}
if (imageRequest.status !== 200) {
console.error("error uploading the image");
}
};
return imageRequest;
}).catch((error) => {
console.error("error uploading the image ", error);
});
fun sendImage(file: File){
client.uploadAttachment(file, object : NexmoRequestListener<NexmoImage> {
override fun onSuccess(image: NexmoImage?) {
val message = image?.original?.let { NexmoMessage.fromImage(it.url) }
if (message != null) {
conversation?.sendMessage(message, object: NexmoRequestListener<Void?> {
override fun onError(apiError: NexmoApiError) {
Log.d("TAG", "Error: failed to send message, ${apiError.message}")
}
override fun onSuccess(aVoid: Void?) {}
})
}
}
override fun onError(error: NexmoApiError) {
Log.d("TAG", "Error: Image not uploaded, ${error.message}")
}
})
}
public void sendImage(File file){
client.uploadAttachment(file, new NexmoRequestListener<NexmoImage>() {
@Override
public void onSuccess(@Nullable NexmoImage result) {
if (result != null){
NexmoMessage message = NexmoMessage.fromImage(result.getOriginal().getUrl());
conversation.sendMessage(message, new NexmoRequestListener<Void>() {
@Override
public void onError(@NonNull NexmoApiError error) {
Log.d("TAG", "Error: failed to send message, " + error.getMessage());
}
@Override
public void onSuccess(@Nullable Void result) {}
});
}
}
@Override
public void onError(@NonNull NexmoApiError error) {
Log.d("TAG", "Error: Image not uploaded, " + error.getMessage());
}
});
}
let image = UIImage(named: "file.png")
guard let imageData = image?.pngData() else { return }
client.uploadAttachment(with: .image, name: "File name", data: imageData) { error, data in
if let error = error {
print("Error sending image: \(error.localizedDescription)")
return
}
if let imageObject = data?["original"] as? [String: Any],
let imageUrl = imageObject["url"] as? String {
let imageMessage = NXMMessage(imageUrl: imageUrl)
conversation.sendMessage(imageMessage, completionHandler: { [weak self] (error) in
...
})
}
}
NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"file.png"]);
[self.client uploadAttachmentWithType:NXMAttachmentTypeImage
name:@"File name 2"
data:imageData
completionHandler:^(NSError * _Nullable error, NSDictionary * _Nullable data) {
if (error == nil) {
NSLog(@"Error sending image");
}
NSString *imageUrl = [data valueForKeyPath:@"original.url"];
NXMMessage *imageMessage = [[NXMMessage alloc] initWithImageUrl:imageUrl];
[conversation sendMessage:message completionHandler:^(NSError * _Nullable error) {
...
}];
}];
Recibir una URL de imagen
A message se recibirá cuando un miembro envíe una imagen a una conversación:
conversation.on('message', (sender, event) => {
if (event.body.message_type === 'image'){
console.log('*** Image sender: ', sender);
console.log('*** Image event: ', event);
}
});
private val messageListener = object : NexmoMessageEventListener {
override fun onTypingEvent(typingEvent: NexmoTypingEvent) {}
override fun onMessageEvent(messageEvent: NexmoMessageEvent) {
val userName = messageEvent.embeddedInfo.user.name
val imageURL = messageEvent.message.imageUrl
Log.d("TAG", "Message received. User $userName : $imageURL")
}
override fun onAttachmentEvent(attachmentEvent: NexmoAttachmentEvent) {}
override fun onTextEvent(textEvent: NexmoTextEvent) {}
override fun onSeenReceipt(seenEvent: NexmoSeenEvent) {}
override fun onEventDeleted(deletedEvent: NexmoDeletedEvent) {}
override fun onDeliveredReceipt(deliveredEvent: NexmoDeliveredEvent) {}
}
conversation?.addMessageEventListener(messageListener)
private NexmoMessageEventListener messageListener = new NexmoMessageEventListener() {
@Override
public void onTextEvent(@NonNull NexmoTextEvent textEvent) {}
@Override
public void onMessageEvent(@NonNull NexmoMessageEvent messageEvent) {
String userName = messageEvent.getEmbeddedInfo().getUser().getName();
String imageURL = messageEvent.getMessage().getImageUrl();
Log.d("TAG", "Message received. User " + userName + " : " + imageURL);
}
@Override
public void onAttachmentEvent(@NonNull NexmoAttachmentEvent attachmentEvent) {}
@Override
public void onEventDeleted(@NonNull NexmoDeletedEvent deletedEvent) {}
@Override
public void onSeenReceipt(@NonNull NexmoSeenEvent seenEvent) {}
@Override
public void onDeliveredReceipt(@NonNull NexmoDeliveredEvent deliveredEvent) {}
@Override
public void onTypingEvent(@NonNull NexmoTypingEvent typingEvent) {}
};
conversation.addMessageEventListener(messageListener);
Añadir NXMConversationDelegate como extensión de un ViewController o similar, y aplicar conversation(_ conversation: NXMConversation, didReceive event: NXMMessageEvent):
Nota: El primer método siguiente es necesario cuando se aplica NXMConversationDelegate:
extension ViewController: NXMConversationDelegate {
func conversation(_ conversation: NXMConversation, didReceive error: Error) {
NSLog("Conversation error: \(error.localizedDescription)")
}
func conversation(_ conversation: NXMConversation, didReceive event: NXMMessageEvent) {
NSLog("Received image: \(event.imageUrl)")
}
}
Tener un ViewControllero similar, se ajustan a NXMConversationDelegate y aplicar conversation:didReceiveMessageEvent::
Nota: El primer método siguiente es necesario cuando se aplica NXMConversationDelegate:
- (void)conversation:(NXMConversation *)conversation didReceive:(NSError *)error {
NSLog(@"Conversation error: %@", error.localizedDescription);
}
- (void)conversation:(NXMConversation *)conversation didReceiveMessageEvent:(NXMMessageEvent *)event {
NSLog(@"Received image event: %@", event.imageUrl);
}
Descargar imágenes de Vonage
Cliente web
Para descargar una imagen es necesario utilizar la función Obtener imagen método.
Cliente móvil (Android, iOS)
Para descargar una imagen es necesario añadir JWT a la solicitud de recuperación de imagen. El JWT se pasa como una cabecera de autorización (Authorization: Bearer <JWT> ). Este es el JWT que se utilizó para iniciar la sesión del usuario.
Varias librerías de imágenes manejan las cabeceras de las peticiones de forma diferente, así que a continuación encontrarás ejemplos de las librerías más populares. Observe que el JWT se establece como Authorization de la solicitud:
// ==== LOAD IMAGE USING COIL ====
// https://github.com/coil-kt/coil
private fun loadImageUsingCoil(url: String, jwt: String, context: Context) {
imageView.load(
Uri.parse(url),
context.imageLoader,
) {
addHeader("Authorization", "bearer $jwt")
}
}
// ==== LOAD IMAGE USING GLIDE ====
// https://github.com/bumptech/glide
private fun loadImageUsingGlide(url: String, jwt: String, context: Context) {
val build = LazyHeaders.Builder()
.addHeader("Authorization", "bearer $jwt")
.build()
val glideUrl = GlideUrl(url, build)
Glide.with(context)
.load(glideUrl)
.into(imageView)
}
// ==== LOAD IMAGE USING PICASSO ====
// https://github.com/square/picasso
// Define custom Authentication interceptor
class AuthenticationInterceptor(private val jwt: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.request().let {
val newRequest = it.newBuilder()
.header("Authorization", "bearer $jwt")
.build()
chain.proceed(newRequest)
}
}
// Create Picasso instance that uses the Authenticator
private fun getPicassoInstance(jwt: String): Picasso {
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthenticationInterceptor(jwt))
.build()
return Picasso.Builder(requireContext()).downloader(OkHttp3Downloader(okHttpClient)).build()
}
// Load image using custom picasso instance (that under the hood uses the authentication interceptor)
private fun loadImageUsingPicasso(url: String, jwt: String, context: Context) {
getPicassoInstance(jwt)
.load(url)
.into(imageView)
}
// ==== LOAD IMAGE USING GLIDE ====
// https://github.com/bumptech/glide
private void loadImageUsingGlide(String url, String jwt, Context context) {
LazyHeaders build = new LazyHeaders.Builder()
.addHeader("Authorization", "bearer " + jwt)
.build();
GlideUrl glideUrl = new GlideUrl(url, build);
Glide.with(context)
.load(glideUrl)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView);
}
// ==== LOAD IMAGE USING PICASSO ====
// https://github.com/square/picasso
// Define custom Authentication interceptor
class AuthenticationInterceptor implements Interceptor {
private String jwt;
public AuthenticationInterceptor(String jwt) {
this.jwt = jwt;
}
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
Request newRequest = request.newBuilder()
.header("Authorization", "bearer " + jwt)
.build();
return chain.proceed(newRequest);
}
}
// Create Picasso instance that uses the Authenticator
private Picasso getPicassoInstance(String jwt) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new AuthenticationInterceptor(jwt))
.build();
return new Picasso.Builder(requireContext())
.downloader(new OkHttp3Downloader(okHttpClient))
.build();
}
// Load image using custom picasso instance (that under the hood uses the authentication interceptor)
private void loadImageUsingPicasso(String url, String jwt, Context context) {
getPicassoInstance(jwt)
.load(url)
.into(imageView);
}
Puede descargar la imagen utilizando URLSession:
func loadImage(urlString: String, token: String, completionHandler: @escaping (UIImage?) -> Void) {
if let url = URL(string: urlString) {
var request = URLRequest(url: url)
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode),
error == nil else {
completionHandler(nil)
return
}
completionHandler(UIImage(data: data))
}
task.resume()
}
}
Al llamar a la función anterior, asegúrese de actualizar su UIImageView en el hilo principal:
loadImage(urlString: "IMAGE_URL", token: "JWT") { image in
if let image = image {
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
Puede descargar la imagen utilizando URLSession:
- (void)loadImageWithURLString:(NSString *)urlString
token:(NSString *)token
completionHandler:(void (^_Nonnull)(UIImage * _Nullable image))completionHandler {
NSURL *url = [[NSURL alloc] initWithString:urlString];
if (url) {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:[NSString stringWithFormat:@"Bearer %@", token] forHTTPHeaderField:@"Authorization"];
NSURLSessionTask *task = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error && data && response) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if (httpResponse.statusCode >= 200 && httpResponse.statusCode <= 299) {
completionHandler([[UIImage alloc] initWithData:data]);
}
}
completionHandler(nil);
}];
[task resume];
}
}
Al llamar a la función anterior, asegúrese de actualizar su UIImageView en el hilo principal:
[self loadImageWithURLString:@"IMAGE_URL" token:@"JWT" completionHandler:^(UIImage * _Nullable image) {
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.imageView setImage:image];
});
}
}];