If you’ve just switched to the latest version of Android Studio (3.6), and you don’t see any option to generate a signed APK, you should take a look at the “Build: Sync” window in the IDE. Let’s look at such a case, here:
Here we have an Android Studio project, but we cannot see the “Generate Signed Bundle / APK…” menu item. How did this happen?
In this case, I opened Android Studio, and closed all projects. Then, I clicked the link to “Import an Android code sample”. I chose Cloud Doorbell, and when the project opened, I saw a number of errors. You can see those errors in the screenshot above. I wanted to build an APK, but when I clicked the “Build” menu, that menu item was missing. It was frustrating because there was no mention in the menu about what was wrong.
However, under the “Build: Sync” window, I saw:
ERROR: Failed to find Build Tools revision 26.0.2
Install Build Tools 26.0.2 and sync project
Upgrade plugin to version 3.6.1 and sync project
Those two lines were links, and when I clicked the first one, the latest Build Tools were installed. I believe it also did a gradle sync on its own.
So, if you run into this problem, take a look at that “Build: Sync” window. If it’s not open already, you can open it by clicking on the “Build” tab at the bottom of the Android Studio IDE. If you see errors there, fix them before trying to do anything else. Otherwise, you may wind up banging your head against a wall… 🙂
Here’s a quick tutorial to get you started playing an mp3 file in an Android app that was built using React Native. This tutorial was developed using Linux (Ubuntu 16.04), React Native 0.61.5, and the React Native Sound package 0.11.0.
First, make your project directory. Let’s call it AudioTmp. In a terminal window, do this:
npx react-native init AudioTmp
cd AudioTmp
All of the following commands assume you’ve got your terminal window open, and you’re standing in the root directory of your project (in AudioTmp, where App.js is located).
You’ll need some extra packages, so run these install commands:
Next, make the utils directory under your project root:
mkdir utils
Add a new file called SoundPlayer.js in the utils directory. Here’s the source for that:
/**
* Really simple demo of https://www.npmjs.com/package/react-native-sound
*/
const Sound = require('react-native-sound');
/**
* Audio credit:
* https://freemusicarchive.org/music/John_Bartmann/Public_Domain_Soundtrack_Music_Album_One/earning-happiness
* "Earning Happiness" by John Bartmann licensed under a CC0 1.0 Universal License
* https://creativecommons.org/publicdomain/zero/1.0/
*/
const FILENAME = 'john_bartmann_04_earning_happiness.mp3';
class SoundPlayer {
constructor(props) {
console.log("SoundPlayer constructor");
};
stopSound() {
console.log('SoundPlayer.stopSound');
this.whoosh.stop();
this.whoosh.release();
}
playSound() {
console.log('SoundPlayer.playSound');
let me = this;
me.whoosh = new Sound(FILENAME, Sound.MAIN_BUNDLE, error => {
if (error) {
console.log('failed to load the sound', error);
return;
}
// loaded successfully
console.log(
'duration in seconds: ' +
me.whoosh.getDuration() +
'number of channels: ' +
me.whoosh.getNumberOfChannels()
);
me.whoosh.play(success => {
if (success) {
console.log('successfully finished playing');
} else {
console.log('playback failed due to audio decoding errors');
}
});
});
}
}
export default SoundPlayer;
Replace the code in App.js with this code:
/**
* Simple demo of https://www.npmjs.com/package/react-native-sound
* The app plays an included mp3 file when the user clicks on 'Play' button.
* It stops the playback when the user clicks on the 'Stop' button.
*/
import React from 'react';
import {
StyleSheet,
View,
Text,
Button
} from 'react-native';
import {
Colors
} from 'react-native/Libraries/NewAppScreen';
/** Keep all sound functionality in separate utils area */
import SoundPlayer from './utils/SoundPlayer';
class App extends React.Component {
constructor(props) {
super(props);
this.soundPlayer = new SoundPlayer();
}
onPlayPress() {
console.log('onPlayPress method');
this.soundPlayer.playSound();
}
onStopPress() {
console.log('onPlayPress method');
this.soundPlayer.stopSound();
}
render() {
return (
<View style={styles.body}>
<Text style={styles.sectionTitle}>Click button to Play</Text>
<View style={styles.buttonStyle}>
<Button style={styles.buttonStyle}
onPress={this.onPlayPress.bind(this)}
title="Play"
/>
</View>
<Text style={styles.sectionTitle}>Click button to Stop</Text>
<View style={styles.buttonStyle}>
<Button buttonStyle={styles.buttonStyle}
onPress={this.onStopPress.bind(this)}
title="Stop"
/>
</View>
</View>
);
}
};
const styles = StyleSheet.create({
body: {
backgroundColor: Colors.white,
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: 'gainsboro'
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
padding: 20,
backgroundColor: 'gainsboro' /* See https://reactnative.dev/docs/colors */,
},
buttonStyle: {
padding: 20,
backgroundColor: 'gainsboro' /* See https://reactnative.dev/docs/colors */,
}
});
export default App;
Run the Android Emulator:
emulator -no-snapshot -avd Galaxy_Nexus_API_28
Start your Metro server:
npx react-native start
Install the app in your Android Emulator:
npx react-native run-android
I see these warnings at my command line, but everything seems to work okay:
error React Native CLI uses autolinking for native dependencies, but the following modules are linked manually:
- react-native-sound (to unlink run: "react-native unlink react-native-sound")
This is likely happening when upgrading React Native from below 0.60 to 0.60 or above. Going forward, you can unlink this dependency via "react-native unlink <dependency>" and it will be included in your app automatically. If a library isn't compatible with autolinking, disregard this message and notify the library maintainers.
Read more about autolinking: https://github.com/react-native-community/cli/blob/master/docs/autolinking.md
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 875 file(s) to forward-jetify. Using 8 workers...
Then it just works! You can hit the Play and Stop buttons to play the audio.
One remark: when I initially created this project, I didn’t use the link command, because the React Native documentation indicated it was not needed for version 0.60. However, that turned out to be untrue! You can save yourself time by doing it the way I’ve done it in this tutorial. When using link, the demo worked immediately, and I didn’t have to make any changes to gradle files.