ESP-32 is still quite new, therefore uploading a sketch is not as straightforward as with ESP-8266. It's still easy though if you follow below steps:

Install Python

First, install Python 2.7 if you don't already have.

https://www.python.org/download/releases/2.7/

Then install python library called wget using pip.

pip install wget

The above is needed for all operating systems. Things are still almost the same in Windows, Linux or MacOS.

Install ESP-32 drivers (for Windows users)

Windows users need to install some drivers. Linux and MacOS users can skip this step.

Go to below address:

https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

download and install CP210x_Universal_Windows_Driver.zip

Install ESP-32 board manager

You cannot install ESP-32 by boards manager in Arduino IDE (at least in June 2018). Additional Boards Manager URLs is no use when installing ESP-32.

You need to create a new folder \hardware\espressif under your sketchbook folder. If you don't know this location simply open Arduino IDE. Then go to Preferences and see Sketchbook location section at the top. Then change this location wherever needed in the below command list.

For me it was "C:\Users\Aliustaoglu\Documents\Arduino". Change yours accordingly

arduino-location

For Windows

It is quite simple for Windows. Execute below commands one by one. It will first get the source code from git and then download necessary files to the location where Arduino IDE will be looking for.

My sketchbook location was C:\Users\Aliustaoglu\Documents\Arduino for Windows-10.

md C:\Users\Aliustaoglu\Documents\Arduino\hardware\espressif
cd C:\Users\Aliustaoglu\Documents\Arduino\hardware\espressif
git clone https://github.com/espressif/arduino-esp32.git esp32
cd esp32
git submodule update --init --recursive
cd tools
get.exe

It might take a while. But after the download and installation finishes, you should be able to see the list of ESP-32 devices under board menu. You don't need to go to Boards Manager anymore.

WindowsInstallation

For Linux and Mac OS

My sketchbook location was /Users/cuneytaliustaoglu/Documents/Arduino for Mac OS.

It is almost the same for UNIX users. Execute below steps:

mkdir -p /Users/cuneytaliustaoglu/Documents/Arduino/hardware/espressif
cd /Users/cuneytaliustaoglu/Documents/Arduino/hardware/espressif
git clone https://github.com/espressif/arduino-esp32.git esp32
cd esp32
git submodule update --init --recursive
cd tools
python get.py

But I got an error while executing the last step

IOError: [Errno socket error] [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:726

If you get this error change the contents of get.py with the one below. Open a text editor:

sudo nano get.py

and replace whole content with below:

#!/usr/bin/env python
# This script will download and extract required tools into the current directory.
# Tools list is obtained from package/package_esp8266com_index.template.json file.
# Written by Ivan Grokhotkov, 2015.
#
from __future__ import print_function
import os
import shutil
import errno
import os.path
import hashlib
import json
import platform
import sys
import tarfile
import zipfile
import re
import wget
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
if sys.version_info[0] == 3:
    from urllib.request import urlretrieve
else:
    # Not Python 3 - today, it is most likely to be Python 2
    from urllib import urlretrieve

if 'Windows' in platform.system():
    import requests

current_dir = os.path.dirname(os.path.realpath(unicode(__file__)))
dist_dir = current_dir + '/dist/'

def sha256sum(filename, blocksize=65536):
    hash = hashlib.sha256()
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            hash.update(block)
    return hash.hexdigest()

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno != errno.EEXIST or not os.path.isdir(path):
            raise

def report_progress(count, blockSize, totalSize):
    percent = int(count*blockSize*100/totalSize)
    percent = min(100, percent)
    sys.stdout.write("\r%d%%" % percent)
    sys.stdout.flush()

def unpack(filename, destination):
    dirname = ''
    print('Extracting {0}'.format(os.path.basename(filename)))
    sys.stdout.flush()
    if filename.endswith('tar.gz'):
        tfile = tarfile.open(filename, 'r:gz')
        tfile.extractall(destination)
        dirname= tfile.getnames()[0]
    elif filename.endswith('zip'):
        zfile = zipfile.ZipFile(filename)
        zfile.extractall(destination)
        dirname = zfile.namelist()[0]
    else:
        raise NotImplementedError('Unsupported archive type')

    # a little trick to rename tool directories so they don't contain version number
    rename_to = re.match(r'^([a-z][^\-]*\-*)+', dirname).group(0).strip('-')
    if rename_to != dirname:
        print('Renaming {0} to {1}'.format(dirname, rename_to))
        if os.path.isdir(rename_to):
            shutil.rmtree(rename_to)
        shutil.move(dirname, rename_to)

def get_tool(tool):
    sys_name = platform.system()
    archive_name = tool['archiveFileName']
    local_path = dist_dir + archive_name
    url = tool['url']
    #real_hash = tool['checksum'].split(':')[1]
    if not os.path.isfile(local_path):
        print('Downloading ' + archive_name);
        sys.stdout.flush()
        if 'CYGWIN_NT' in sys_name:
            import ssl
            ctx = ssl.create_default_context()
            ctx.check_hostname = False
            ctx.verify_mode = ssl.CERT_NONE
            urlretrieve(url, local_path, report_progress, context=ctx)
        elif 'Windows' in sys_name:
            r = requests.get(url)
            f = open(local_path, 'wb')
            f.write(r.content)
            f.close()
        else:
            #urlretrieve(url, local_path, report_progress)
            wget.download(url, local_path)
        sys.stdout.write("\rDone\n")
        sys.stdout.flush()
    else:
        print('Tool {0} already downloaded'.format(archive_name))
        sys.stdout.flush()
    #local_hash = sha256sum(local_path)
    #if local_hash != real_hash:
    #    print('Hash mismatch for {0}, delete the file and try again'.format(local_path))
    #    raise RuntimeError()
    unpack(local_path, '.')

def load_tools_list(filename, platform):
    tools_info = json.load(open(filename))['packages'][0]['tools']
    tools_to_download = []
    for t in tools_info:
        tool_platform = [p for p in t['systems'] if p['host'] == platform]
        if len(tool_platform) == 0:
            continue
        tools_to_download.append(tool_platform[0])
    return tools_to_download

def identify_platform():
    arduino_platform_names = {'Darwin'  : {32 : 'i386-apple-darwin',   64 : 'x86_64-apple-darwin'},
                              'Linux'   : {32 : 'i686-pc-linux-gnu',   64 : 'x86_64-pc-linux-gnu'},
                              'LinuxARM': {32 : 'arm-linux-gnueabihf', 64 : 'aarch64-linux-gnu'},
                              'Windows' : {32 : 'i686-mingw32',        64 : 'i686-mingw32'}}
    bits = 32
    if sys.maxsize > 2**32:
        bits = 64
    sys_name = platform.system()
    sys_platform = platform.platform()
    print('System: %s, Info: %s' % (sys_name, sys_platform))
    if 'Linux' in sys_name and sys_platform.find('arm') > 0:
        sys_name = 'LinuxARM'
    if 'CYGWIN_NT' in sys_name:
        sys_name = 'Windows'
    return arduino_platform_names[sys_name][bits]

if __name__ == '__main__':
    identified_platform = identify_platform()
    print('Platform: {0}'.format(identified_platform))
    tools_to_download = load_tools_list(current_dir + '/../package/package_esp32_index.template.json', identified_platform)
    mkdir_p(dist_dir)
    for tool in tools_to_download:
        get_tool(tool)
    print('Done')

Now if you restart Arduino IDE, you will see the list of ESP-32 devices.