Repository: cawfree/react-native-quiet Branch: master Commit: 262872573f85 Files: 66 Total size: 150.9 KB Directory structure: gitextract_0_93nju_/ ├── .gitattributes ├── .gitignore ├── .npmignore ├── README.md ├── android/ │ ├── README.md │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── io/ │ └── github/ │ └── cawfree/ │ └── quiet/ │ ├── RNQuietModule.java │ └── RNQuietPackage.java ├── example/ │ ├── .buckconfig │ ├── .flowconfig │ ├── .gitattributes │ ├── .gitignore │ ├── .watchmanconfig │ ├── App.js │ ├── __tests__/ │ │ └── App-test.js │ ├── android/ │ │ ├── app/ │ │ │ ├── BUCK │ │ │ ├── build.gradle │ │ │ ├── build_defs.bzl │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── debug/ │ │ │ │ └── AndroidManifest.xml │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── example/ │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res/ │ │ │ └── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradle.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── keystores/ │ │ │ ├── BUCK │ │ │ └── debug.keystore.properties │ │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios/ │ │ ├── Podfile │ │ ├── example/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj/ │ │ │ │ └── LaunchScreen.xib │ │ │ ├── Images.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ └── main.m │ │ ├── example-tvOS/ │ │ │ └── Info.plist │ │ ├── example-tvOSTests/ │ │ │ └── Info.plist │ │ ├── example.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ │ ├── example.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── exampleTests/ │ │ ├── Info.plist │ │ └── exampleTests.m │ ├── metro.config.js │ └── package.json ├── index.js ├── ios/ │ ├── Podfile │ ├── RNQuiet.h │ ├── RNQuiet.m │ ├── RNQuiet.xcodeproj/ │ │ └── project.pbxproj │ └── RNQuiet.xcworkspace/ │ └── contents.xcworkspacedata ├── package.json ├── react-native-quiet.podspec └── scripts/ └── examples_postinstall.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.pbxproj -text ================================================ FILE: .gitignore ================================================ # OSX # .DS_Store # node.js # node_modules/ npm-debug.log yarn-error.log # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate project.xcworkspace # Android/IntelliJ # build/ .idea .gradle local.properties *.iml # BUCK buck-out/ \.buckd/ *.keystore ios/Pods/ example/ios/Pods/ android/org.quietmodem.Quiet/build/ example/android/app/build ================================================ FILE: .npmignore ================================================ example ================================================ FILE: README.md ================================================ # react-native-quiet This is a [**React Native**](https://facebook.github.io/react-native/) wrapper around the [**Quiet Project**](https://github.com/quiet/quiet), which enables the transfer of data using sound as the transfer medium. This has a number of benefits: - Super cross-platform. (You just need a microphone and a speaker.) - Broadcast to devices within range without pairing. - No network connection required. Quiet can even go _ultrasonic_, allowing us to communicate without impacting on noise levels that are perceptible by human ears. Try the awesome online demo [**here**](https://quiet.github.io/quiet-js/). ## 🚀 Getting started Using [`npm`](): ```bash $ npm install react-native-quiet --save ``` Using [`yarn`](): ```bash yarn add react-native-quiet ``` #### Android This project relies upon the [**Android NDK**](https://developer.android.com/ndk); please make sure this is configured within your system path. Android relies upon caching the [**Quiet Android Project**](https://github.com/quiet/org.quietmodem.Quiet), meaning that we have to manually configure it's visibility to your compiled application. To do this, in your `/android/settings.gradle`, append the `:quiet` native project, which is packaged inside of `react-native-quiet`: ```java include ':quiet' project(':quiet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-quiet/android/Transducer/quiet') ``` Finally, under **File > Project Structure**, be sure to define your `Android NDK location` under **SDK Location**. You can just use the dropdown to select the default location. #### iOS On iOS, after installing be sure to sync your Cocoapods via `pod install`. ### Upgrading #### 0.1.0 **android/settings.xml** ```diff include ':quiet' - project(':quiet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-quiet/android/org.quietmodem.Quiet/quiet') + project(':quiet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-quiet/android/Transducer/quiet') ``` ## ✍️ Example This project exposes high level functionality to send and receive messages using near-ultrasound. Simply start the library, use `send()` to transmit a message string and `addListener` to listen to receive sent messages. Be careful; you can hear your own messages. ```javascript import Quiet from 'react-native-quiet'; // Start listening. (This will ask for microphone permissions!) (async() => { await Quiet.start("ultrasonic-experimental"); const { unsubscribe } = Quiet .addListener(msg => console.warn(msg)); Quiet.send("hello, world!"); await new Promise(resolve => setTimeout(resolve, 10000)); Quiet.stop(); unsubscribe(); })(); ``` ### ✌️ License [**MIT**](https://opensource.org/licenses/MIT) ================================================ FILE: android/README.md ================================================ README ====== If you want to publish the lib as a maven dependency, follow these steps before publishing a new version to npm: 1. Be sure to have the Android [SDK](https://developer.android.com/studio/index.html) and [NDK](https://developer.android.com/ndk/guides/index.html) installed 2. Be sure to have a `local.properties` file in this folder that points to the Android SDK and NDK ``` ndk.dir=/Users/{username}/Library/Android/sdk/ndk-bundle sdk.dir=/Users/{username}/Library/Android/sdk ``` 3. Delete the `maven` folder 4. Run `./gradlew installArchives` 5. Verify that latest set of generated files is in the maven folder with the correct version number ================================================ FILE: android/build.gradle ================================================ // android/build.gradle def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } buildscript { // The Android Gradle plugin is only required when opening the android folder stand-alone. // This avoids unnecessary downloads and potential conflicts when the library is included as a // module dependency in an application project. if (project == rootProject) { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' } } } apply plugin: 'com.android.library' apply plugin: 'maven' // Matches values in recent template from React Native 0.59 / 0.60 // https://github.com/facebook/react-native/blob/0.59-stable/template/android/build.gradle#L5-L9 // https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle#L5-L9 def DEFAULT_COMPILE_SDK_VERSION = 28 def DEFAULT_BUILD_TOOLS_VERSION = "28.0.3" def DEFAULT_MIN_SDK_VERSION = 16 def DEFAULT_TARGET_SDK_VERSION = 28 android { compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) defaultConfig { minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) versionCode 1 versionName "1.0" } lintOptions { abortOnError false } } repositories { mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" } maven { // Android JSC is installed from npm url "$rootDir/../node_modules/jsc-android/dist" } maven { // Android Quiet is packaged by react-native-quiet. url "$rootDir/../node_modules/react-native-quiet/android/Transducer/quiet" } google() jcenter() } dependencies { // ref: // https://github.com/facebook/react-native/blob/0.61-stable/template/android/app/build.gradle#L192 //noinspection GradleDynamicVersion implementation 'com.facebook.react:react-native:+' // From node_modules implementation project(':quiet') } def configureReactNativePom(def pom) { def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text) pom.project { name packageJson.title artifactId packageJson.name version = packageJson.version group = "io.github.cawfree.quiet" description packageJson.description url packageJson.repository.baseUrl licenses { license { name packageJson.license url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename distribution 'repo' } } developers { developer { id packageJson.author.username name packageJson.author.name } } } } afterEvaluate { project -> // some Gradle build hooks ref: // https://www.oreilly.com/library/view/gradle-beyond-the/9781449373801/ch03.html task androidJavadoc(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += files(android.bootClasspath) classpath += files(project.getConfigurations().getByName('compile').asList()) include '**/*.java' } task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) { classifier = 'javadoc' from androidJavadoc.destinationDir } task androidSourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs include '**/*.java' } android.libraryVariants.all { variant -> def name = variant.name.capitalize() task "jar${name}"(type: Jar, dependsOn: variant.javaCompile) { from variant.javaCompile.destinationDir } } artifacts { archives androidSourcesJar archives androidJavadocJar } task installArchives(type: Upload) { configuration = configurations.archives repositories.mavenDeployer { // Deploy to react-native-event-bridge/maven, ready to publish to npm repository url: "file://${projectDir}/../android/maven" configureReactNativePom pom } } } ================================================ FILE: android/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/src/main/java/io/github/cawfree/quiet/RNQuietModule.java ================================================ package io.github.cawfree.quiet; import android.Manifest; import android.content.pm.PackageManager; import android.os.AsyncTask; import androidx.core.content.ContextCompat; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.modules.core.DeviceEventManagerModule; import org.quietmodem.Quiet.*; import java.util.Arrays; public class RNQuietModule extends ReactContextBaseJavaModule { /* Static Declations. */ private static final String TAG = "RNQuiet"; /* Static, modisiable variables. (Antipattern!) */ private static FrameTransmitter FRAME_TRANSMITTER = null; private static FrameReceiver FRAME_RECEIVER = null; private final ReactApplicationContext reactContext; public RNQuietModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; } @Override public String getName() { return RNQuietModule.TAG; } @ReactMethod public final void start(final String pKey) { // Place the beacon back into the initial state. this.stop(); // Check if we have permission. final boolean hasPermission = ContextCompat.checkSelfPermission(this.reactContext, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED; // Do we have permission? if (hasPermission) { try { FRAME_TRANSMITTER = new FrameTransmitter( new FrameTransmitterConfig( this.reactContext, pKey ) ); FRAME_RECEIVER = new FrameReceiver( new FrameReceiverConfig( this.reactContext, pKey ) ); new AsyncTask() { @Override protected final Void doInBackground(final Void... pIsUnused) { final byte[] buf = new byte[1024]; while(FRAME_RECEIVER != null) { try { // Block and wait for updates. FRAME_RECEIVER.setBlocking(0, 0); // Wait for the FRAME_RECEIVER to return. final int numberOfBytes = (int)FRAME_RECEIVER.receive(buf); RNQuietModule.this.reactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("onMessageReceived", new String(Arrays.copyOfRange(buf, 0, numberOfBytes), "UTF-8")); } catch (final Exception pException) { // Print the Stack Trace. pException.printStackTrace(); } } return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } catch(final Exception pException) { // Print the Stack Trace. pException.printStackTrace(); // Stop running. this.stop(); } } } @ReactMethod public final void send(final String pMessage) { try { if (FRAME_TRANSMITTER != null) { // Transmit the message. FRAME_TRANSMITTER.send(pMessage.getBytes()); } } catch (final Exception pException) { // Print the Stack Trace. pException.printStackTrace(); } } /** TODO: Actually close the resources. **/ @ReactMethod public final void stop() { if (FRAME_TRANSMITTER != null) { // Nullify. FRAME_TRANSMITTER = null; } if (FRAME_RECEIVER != null) { //Nullify. FRAME_RECEIVER = null; } } } ================================================ FILE: android/src/main/java/io/github/cawfree/quiet/RNQuietPackage.java ================================================ package io.github.cawfree.quiet; import java.util.Arrays; import java.util.Collections; import java.util.List; import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.bridge.JavaScriptModule; public class RNQuietPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { return Arrays.asList(new RNQuietModule(reactContext)); } @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } } ================================================ FILE: example/.buckconfig ================================================ [android] target = Google Inc.:Google APIs:23 [maven_repositories] central = https://repo1.maven.org/maven2 ================================================ FILE: example/.flowconfig ================================================ [ignore] ; We fork some components by platform .*/*[.]android.js ; Ignore "BUCK" generated dirs /\.buckd/ ; Ignore unexpected extra "@providesModule" .*/node_modules/.*/node_modules/fbjs/.* ; Ignore duplicate module providers ; For RN Apps installed via npm, "Libraries" folder is inside ; "node_modules/react-native" but in the source repo it is in the root .*/Libraries/react-native/React.js ; Ignore polyfills .*/Libraries/polyfills/.* ; Ignore metro .*/node_modules/metro/.* [include] [libs] node_modules/react-native/Libraries/react-native/react-native-interface.js node_modules/react-native/flow/ [options] emoji=true esproposal.optional_chaining=enable esproposal.nullish_coalescing=enable module.system=haste module.system.haste.use_name_reducers=true # get basename module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' # strip .js or .js.flow suffix module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' # strip .ios suffix module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' module.system.haste.paths.blacklist=.*/__tests__/.* module.system.haste.paths.blacklist=.*/__mocks__/.* module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* munge_underscores=true module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' module.file_ext=.js module.file_ext=.jsx module.file_ext=.json module.file_ext=.native.js suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] ^0.92.0 ================================================ FILE: example/.gitattributes ================================================ *.pbxproj -text ================================================ FILE: example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate project.xcworkspace # Android/IntelliJ # build/ .idea .gradle local.properties *.iml # node.js # node_modules/ npm-debug.log yarn-error.log # BUCK buck-out/ \.buckd/ *.keystore # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ */fastlane/report.xml */fastlane/Preview.html */fastlane/screenshots # Bundle artifact *.jsbundle ================================================ FILE: example/.watchmanconfig ================================================ {} ================================================ FILE: example/App.js ================================================ import React from 'react'; import { SafeAreaView, View, StyleSheet, TextInput, Text, Button, Image } from 'react-native'; import Quiet from 'react-native-quiet'; const styles = StyleSheet .create( { container: { flex: 1, padding: 15, alignItems: 'center', }, spacing: { marginBottom: 15, }, title: { color: 'white', fontWeight: 'bold', fontSize: 26, marginBottom: 10, }, subtitle: { color: 'white', fontSize: 16, marginBottom: 10, }, textInput: { fontSize: 26, textAlign: 'center', }, logo: { position: 'absolute', bottom: 15, width: 250, height: 100, }, logoContainer:{ flex: 1, alignItems: 'center', justifyContent: 'center', } }, ); export default class App extends React.Component { state = { msg: '', rcv: '', }; onPress = () => { const { msg } = this.state; if (msg && msg.length > 0) { this.setState( { msg: '', }, () => Quiet.send(msg), ); } }; componentDidMount() { Quiet.start( 'ultrasonic-experimental', ); Quiet.addListener( rcv => this.setState( { rcv, }, ), ); } render() { const { msg, rcv } = this.state; return ( <> this.setState( { msg, }, )} value={msg} placeholder="Enter a message." />