initial android support

moved ios specific code into a subfolder
created an android folder
updated the Install instructions on the readme
bumped the version to 0.2.0
This commit is contained in:
Andy Prock 2015-09-24 16:10:24 -07:00
parent 4cb6e77504
commit 3ce4b63536
24 changed files with 874 additions and 26 deletions

View File

@ -13,7 +13,61 @@ This module is used by [Tradle](https://github.com/tradle)
npm install --save react-native-udp
```
* Drag UdpSockets.xcodeproj from node_modules/react-native-udp into your XCode project. Click on the project in XCode, go to Build Phases, then Link Binary With Libraries and add libUdpSockets.a
### `iOS`
* Drag UdpSockets.xcodeproj from node_modules/react-native-udp/ios into your XCode project.
* Click on the project in XCode, go to Build Phases, then Link Binary With Libraries and add `libUdpSockets.a`
### `Android`
* `android/settings.gradle`
```gradle
...
include ':react-native-udp'
project(':react-native-udp').projectDir = new File(settingsDir, '../node_modules/react-native-udp/android')
```
* `android/app/build.gradle`
```gradle
dependencies {
...
compile project(':react-native-udp')
}
```
* register module (in MainActivity.java)
```java
...
import com.tradle.react.*; // <--- import
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.addPackage(new UdpSocketsModule()) // <- add here
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "YourProject", null);
setContentView(mReactRootView);
}
}
```
Buckle up, Dorothy
@ -33,19 +87,19 @@ _only if you want to write require('dgram') in your javascript_
### JS
_see/run index.ios.js for a complete example, but basically it's just like dgram_
_see/run index.js for a complete example, but basically it's just like dgram_
```js
var dgram = require('dgram')
// OR, if not shimming via package.json "browser" field:
// var dgram = require('UdpSockets')
// var dgram = require('UdpSockets')
var socket = dgram.createSocket('udp4')
socket.bind(12345)
socket.once('listening', function() {
var buf = toByteArray('excellent!')
socket.send(buf, 0, buf.length, remotePort, remoteHost, function(err) {
if (err) throw err
console.log('message was sent')
})
})
@ -73,4 +127,6 @@ add select tests from node's tests for dgram
[Ellen Katsnelson](https://github.com/pgmemk)
[Tradle, Inc.](https://github.com/tradle/about/wiki)
[Andy Prock](https://github.com/aprock)
PR's welcome!

View File

@ -1,17 +0,0 @@
/**
* Stub of UdpSockets for Android.
*
* @providesModule UdpSockets
* @flow
*/
'use strict';
var warning = require('warning');
var UdpSockets = {
test: function() {
warning("Not yet implemented for Android.");
}
};
module.exports = UdpSockets;

View File

@ -4,7 +4,7 @@
* @flow
*/
var UdpSocket = require('./UdpSocket.ios')
var UdpSocket = require('./UdpSocket');
exports.createSocket = function(type) {
return new UdpSocket({

31
android/build.gradle Normal file
View File

@ -0,0 +1,31 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "0.2.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// needed for https://github.com/square/okio/issues/58
lintOptions {
warning 'InvalidPackage'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:0.11.+'
}

17
android/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tradle.react" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
</manifest>

View File

@ -0,0 +1,30 @@
/**
* UdpErrorUtil.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import javax.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
/**
* Helper class for udp errors.
*/
public class UdpErrorUtil {
/**
* Create Error object to be passed back to the JS callback.
*/
/* package */ static WritableMap getError(@Nullable String key, String errorMessage) {
WritableMap errorMap = Arguments.createMap();
errorMap.putString("message", errorMessage);
if (key != null) {
errorMap.putString("key", key);
}
return errorMap;
}
}

View File

@ -0,0 +1,116 @@
/**
* UdpReceiverTask.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import android.os.AsyncTask;
import android.util.Base64;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* This is a specialized AsyncTask that receives data from a socket in the background, and
* notifies it's listener when data is received.
*/
public class UdpReceiverTask extends AsyncTask<Void, UdpReceiverTask.ReceivedPacket, Void> {
private static final String TAG = "UdpReceiverTask";
private static final int MAX_UDP_DATAGRAM_LEN = 1024;
private DatagramSocket mSocket;
private WeakReference<OnDataReceivedListener> mReceiverListener;
/**
* An {@link AsyncTask} that blocks to receive data from a socket.
* Received data is sent via the {@link OnDataReceivedListener}
*/
public UdpReceiverTask(DatagramSocket socket, UdpReceiverTask.OnDataReceivedListener
receiverListener) {
this.mSocket = socket;
this.mReceiverListener = new WeakReference<>(receiverListener);
}
/**
* An infinite loop to block and read data from the socket.
*/
@Override
protected Void doInBackground(Void... a) {
OnDataReceivedListener receiverListener = mReceiverListener.get();
try {
byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
while(!isCancelled()){
mSocket.receive(dp);
publishProgress(new ReceivedPacket(Base64.encodeToString(lMsg, Base64.NO_WRAP),
dp.getAddress().getHostAddress(), dp.getPort()));
}
} catch (IOException ioe) {
if (receiverListener != null) {
receiverListener.didReceiveError(ioe.getMessage());
}
} catch (RuntimeException rte) {
if (receiverListener != null) {
receiverListener.didReceiveRuntimeException(rte);
}
}
return null;
}
/**
* Send data out to the listener.
* @param {@link ReceivedPacket} packet marshalled data
*/
@Override
protected void onProgressUpdate(ReceivedPacket... packet) {
OnDataReceivedListener receiverListener = mReceiverListener.get();
if (receiverListener != null) {
receiverListener.didReceiveData(packet[0].base64String, packet[0].address,
packet[0].port);
}
}
/**
* Close if cancelled.
*/
@Override
protected void onCancelled(){
if (mSocket != null){
mSocket.close();
}
}
/**
* Internal class used to marshall packet data as a progress update.
* base64String the data encoded as a base64 string
* address the address of the sender
* port the port number of the sender
*/
class ReceivedPacket {
String base64String;
String address;
int port;
ReceivedPacket(String base64String, String address, int port) {
this.base64String = base64String;
this.address = address;
this.port = port;
}
}
/**
* Listener interface for receive events.
*/
public interface OnDataReceivedListener {
void didReceiveData(String data, String host, int port);
void didReceiveError(String message);
void didReceiveRuntimeException(RuntimeException exception);
}
}

View File

@ -0,0 +1,61 @@
/**
* UdpSenderTask.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import android.os.AsyncTask;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* Specialized AsyncTask that transmits data in the background, and notifies listeners of the result.
*/
public class UdpSenderTask extends AsyncTask<DatagramPacket, Void, Void> {
private static final String TAG = "UdpSenderTask";
private DatagramSocket mSocket;
private WeakReference<OnDataSentListener> mListener;
public UdpSenderTask(DatagramSocket socket, OnDataSentListener listener) {
this.mSocket = socket;
this.mListener = new WeakReference<>(listener);
}
@Override
protected Void doInBackground(DatagramPacket... params) {
OnDataSentListener listener = mListener.get();
try {
mSocket.send(params[0]);
if (listener != null) {
listener.onDataSent(this);
}
} catch (IOException e) {
if (listener != null) {
listener.onDataSentError(this, e.getMessage());
}
} catch (RuntimeException rte) {
if (listener != null) {
listener.onDataSentRuntimeException(this, rte);
}
}
return null;
}
/**
* Callbacks for data send events.
*/
public interface OnDataSentListener {
void onDataSent(UdpSenderTask task);
void onDataSentError(UdpSenderTask task, String error);
void onDataSentRuntimeException(UdpSenderTask task, RuntimeException exception);
}
}

View File

@ -0,0 +1,226 @@
/**
* UdpSocketClient.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.util.Base64;
import com.facebook.react.bridge.Callback;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Client class that wraps a sender and a receiver for UDP data.
*/
public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedListener, UdpSenderTask.OnDataSentListener {
private final OnDataReceivedListener mReceiverListener;
private final OnRuntimeExceptionListener mExceptionListener;
private final boolean mReuseAddress;
private final Map<UdpSenderTask, Callback> mPendingSends;
private DatagramChannel mChannel;
private DatagramSocket mSocket;
private UdpReceiverTask mReceiverTask;
private UdpSocketClient(Builder builder) {
this.mReceiverListener = builder.receiverListener;
this.mExceptionListener = builder.exceptionListener;
this.mReuseAddress = builder.reuse;
this.mPendingSends = new ConcurrentHashMap<>();
}
/**
* Binds to a specific port or address. A random port is used if the address is {@code null}.
*
* @param port local port to bind to
* @param address local address to bind to
* @throws IOException
* @throws IllegalArgumentException
* if the SocketAddress is not supported
* @throws SocketException
* if the socket is already bound or a problem occurs during
* binding.
*/
public void bind(Integer port, @Nullable String address) throws IOException {
mChannel = DatagramChannel.open();
mChannel.configureBlocking(true);
mSocket = mChannel.socket();
mReceiverTask = new UdpReceiverTask(mSocket, this);
SocketAddress socketAddress = null;
if (address != null) {
socketAddress = new InetSocketAddress(address, port);
} else {
socketAddress = new InetSocketAddress(port);
}
mSocket.setReuseAddress(mReuseAddress);
mSocket.bind(socketAddress);
// begin listening for data in the background
mReceiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Creates a UdpSenderTask, and transmits udp data in the background.
*
* @param base64String byte array housed in a String.
* @param port destination port
* @param address destination address
* @param callback callback for results
* @throws UnknownHostException
*/
public void send(String base64String, Integer port, String address, @Nullable Callback callback) throws UnknownHostException {
byte[] data = Base64.decode(base64String, Base64.NO_WRAP);
DatagramPacket packet = new DatagramPacket(data, data.length,
InetAddress.getByName(address), port);
UdpSenderTask task = new UdpSenderTask(mSocket, this);
if (callback != null) {
synchronized (mPendingSends) {
mPendingSends.put(task, callback);
}
}
task.execute(packet);
}
/**
* Sets the socket to enable broadcasts.
*/
public void setBroadcast(boolean flag) throws SocketException {
if (mSocket != null) {
mSocket.setBroadcast(flag);
}
}
/**
* Shuts down the receiver task, closing the socket.
*/
public void close() throws IOException {
if (mReceiverTask != null && !mReceiverTask.isCancelled()) {
mReceiverTask.cancel(false);
} else if (mChannel.isOpen()) {
mChannel.close();
}
}
/**
* Retransmits the data back a level, attaching {@code this}
*/
@Override
public void didReceiveData(String data, String host, int port) {
mReceiverListener.didReceiveData(this, data, host, port);
}
/**
* Retransmits the error back a level, attaching {@code this}
*/
@Override
public void didReceiveError(String message) {
mReceiverListener.didReceiveError(this, message);
}
/**
* Retransmits the exception back a level, attaching {@code this}
*/
@Override
public void didReceiveRuntimeException(RuntimeException exception) {
mExceptionListener.didReceiveException(exception);
}
/**
* Transmits success to the javascript layer, if a callback is present.
*/
@Override
public void onDataSent(UdpSenderTask task) {
Callback callback;
synchronized (mPendingSends) {
callback = mPendingSends.get(task);
mPendingSends.remove(task);
}
if (callback != null) {
callback.invoke();
}
}
/**
* Transmits an error to the javascript layer, if a callback is present.
*/
@Override
public void onDataSentError(UdpSenderTask task, String error) {
Callback callback;
synchronized (mPendingSends) {
callback = mPendingSends.get(task);
mPendingSends.remove(task);
}
if (callback != null) {
callback.invoke(UdpErrorUtil.getError(null, error));
}
}
/**
* Retransmits the exception back a level, attaching {@code this}
*/
@Override
public void onDataSentRuntimeException(UdpSenderTask task, RuntimeException exception) {
mExceptionListener.didReceiveException(exception);
synchronized (mPendingSends) {
mPendingSends.remove(task);
}
}
public static class Builder {
private OnDataReceivedListener receiverListener;
private OnRuntimeExceptionListener exceptionListener;
private boolean reuse = true;
public Builder(OnDataReceivedListener receiverListener, OnRuntimeExceptionListener exceptionListener) {
this.receiverListener = receiverListener;
this.exceptionListener = exceptionListener;
}
public Builder reuseAddress(boolean reuse) {
this.reuse = reuse;
return this;
}
public UdpSocketClient build() {
return new UdpSocketClient(this);
}
}
/**
* Callback interface for runtime exceptions.
*/
public interface OnRuntimeExceptionListener {
void didReceiveException(RuntimeException exception);
}
/**
* Callback interface data received events.
*/
public interface OnDataReceivedListener {
void didReceiveData(UdpSocketClient client, String data, String host, int port);
void didReceiveError(UdpSocketClient client, String message);
}
}

View File

@ -0,0 +1,277 @@
/**
* UdpSockets.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import android.support.annotation.Nullable;
import android.util.SparseArray;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.GuardedAsyncTask;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
/**
* The NativeModule in charge of storing active {@link UdpSocketClient}s, and acting as an api layer.
*/
public final class UdpSockets extends ReactContextBaseJavaModule
implements UdpSocketClient.OnDataReceivedListener, UdpSocketClient.OnRuntimeExceptionListener {
private static final String TAG = "UdpSockets";
private SparseArray<UdpSocketClient> mClients = new SparseArray<>();
private boolean mShuttingDown = false;
public UdpSockets(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return TAG;
}
@Override
public void initialize() {
mShuttingDown = false;
}
@Override
public void onCatalystInstanceDestroy() {
mShuttingDown = true;
// serialize on the AsyncTask thread, and block
try {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
for (int i = 0; i < mClients.size(); i++) {
try {
mClients.valueAt(i).close();
} catch (IOException e) {
FLog.e(TAG, "exception when shutting down", e);
}
}
mClients.clear();
}
}.execute().get();
} catch (InterruptedException e) {
FLog.e(TAG, "onCatalystInstanceDestroy", e);
} catch (ExecutionException e) {
FLog.e(TAG, "onCatalystInstanceDestroy", e);
}
}
/**
* Private method to retrieve clients. Must be called from a GuardedAsyncTask for thread-safety.
*/
private UdpSocketClient findClient(final Integer cId, final Callback callback) {
final UdpSocketClient client = mClients.get(cId);
if (client == null) {
if (callback == null) {
FLog.e(TAG, "missing callback parameter.");
} else {
callback.invoke(UdpErrorUtil.getError(null, "no client found with id " + cId), null);
}
}
return client;
}
/**
* Creates a {@link UdpSocketClient} with the given ID, and options
*/
@ReactMethod
public void createSocket(final Integer cId, final ReadableMap options) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
if (cId == null) {
FLog.e(TAG, "createSocket called with nil id parameter.");
return;
}
UdpSocketClient client = mClients.get(cId);
if (client != null) {
FLog.e(TAG, "createSocket called twice with the same id.");
return;
}
UdpSocketClient.Builder builder = new UdpSocketClient.Builder(UdpSockets.this, UdpSockets.this);
mClients.put(cId, builder.build());
}
}.execute();
}
/**
* Binds to a given port and address, and begins listening for data.
*/
@ReactMethod
public void bind(final Integer cId, final Integer port, final @Nullable String address,
final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
}
try {
client.bind(port, address);
WritableMap result = Arguments.createMap();
result.putString("address", address);
result.putInt("port", port);
callback.invoke(null, result);
} catch (SocketException exception) {
// Socket is already bound or a problem occurred during binding
callback.invoke(UdpErrorUtil.getError(null, exception.getMessage()));
} catch (IllegalArgumentException exception) {
// SocketAddress is not supported
callback.invoke(UdpErrorUtil.getError(null, exception.getMessage()));
} catch (IOException exception) {
// an exception occurred
callback.invoke(UdpErrorUtil.getError(null, exception.getMessage()));
}
}
}.execute();
}
/**
* Sends udp data via the {@link UdpSocketClient}
*/
@ReactMethod
public void send(final Integer cId, final String base64String,
final Integer port, final String address, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
}
try {
client.send(base64String, port, address, callback);
} catch (UnknownHostException e) {
callback.invoke(UdpErrorUtil.getError(null, e.getMessage()));
}
}
}.execute();
}
/**
* Closes a specific client's socket, and removes it from the list of known clients.
*/
@ReactMethod
public void close(final Integer cId, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
}
try {
client.close();
callback.invoke();
} catch (IOException e) {
callback.invoke(UdpErrorUtil.getError(null, e.getMessage()));
}
mClients.remove(cId);
}
}.execute();
}
/**
* Sets the broadcast flag for a given client.
*/
@ReactMethod
public void setBroadcast(final Integer cId, final Boolean flag, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
UdpSocketClient client = findClient(cId, callback);
if (client == null) {
return;
}
try {
client.setBroadcast(flag);
callback.invoke();
} catch (SocketException e) {
callback.invoke(UdpErrorUtil.getError(null, e.getMessage()));
}
}
}.execute();
}
/**
* Notifies the javascript layer upon data receipt.
*/
@Override
public void didReceiveData(final UdpSocketClient socket, final String data, final String host, final int port) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
protected void doInBackgroundGuarded(Void... params) {
int clientID = -1;
for(int i = 0; i < mClients.size(); i++) {
clientID = mClients.keyAt(i);
// get the object by the key.
if (socket.equals(mClients.get(clientID))) {
break;
}
}
if (clientID == -1) {
return;
}
WritableMap eventParams = Arguments.createMap();
eventParams.putString("data", data);
eventParams.putString("address", host);
eventParams.putInt("port", port);
ReactContext reactContext = UdpSockets.this.getReactApplicationContext();
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("udp-" + clientID + "-data", eventParams);
}
}.execute();
}
/**
* Logs an error that happened during or prior to data reception.
*/
@Override
public void didReceiveError(UdpSocketClient client, String message) {
FLog.e(TAG, message);
}
/**
* Sends RuntimeExceptions to the application context handler.
*/
@Override
public void didReceiveException(RuntimeException exception) {
getReactApplicationContext().handleException(exception);
}
}

View File

@ -0,0 +1,43 @@
/**
* UdpSocketsModule.java
* react-native-udp
*
* Created by Andy Prock on 9/24/15.
*/
package com.tradle.react;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class UdpSocketsModule implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new UdpSockets(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -2,16 +2,16 @@
"name": "react-native-udp",
"version": "0.1.0",
"description": "node's dgram API for react-native",
"main": "./UdpSockets.ios.js",
"main": "UdpSockets.js",
"scripts": {
"start": "exit 1"
},
"browser": {
"dgram": "./UdpSockets.ios.js"
"dgram": "./UdpSockets.js"
},
"repository": {
"type": "git",
"url": "https://github.com/tradle/react-native-udp"
"url": "git+https://github.com/tradle/react-native-udp.git"
},
"keywords": [
"react-component",
@ -20,7 +20,8 @@
"dgram",
"udp",
"sockets",
"ios"
"ios",
"android"
],
"author": {
"name": "Mark Vayngrib",