diff --git a/README.md b/README.md
index 9f1049464c3e53fb798d7d9b5f8ae0a8ef2a9bc4..9c4883a22b7474313f7d6a4f3e91615bac40d171 100644
--- a/README.md
+++ b/README.md
@@ -176,11 +176,11 @@ Some utility methods are also available:
     # look up coordinates of some location (like searching Google Maps)
     Geocoder.coordinates("25 Main St, Cooperstown, NY")
      => [42.700149, -74.922767]
-
+    
     # distance between Eiffel Tower and Empire State Building
     Geocoder::Calculations.distance_between([47.858205,2.294359], [40.748433,-73.985655])
      => 3619.77359999382 # in configured units (default miles)
-
+    
     # find the geographic center (aka center of gravity) of objects or points
     Geocoder::Calculations.geographic_center([city1, city2, [40.22,-73.99], city4])
      => [35.14968, -90.048929]
@@ -333,26 +333,26 @@ Some common configuration options are:
 
     # config/initializers/geocoder.rb
     Geocoder.configure(
-
+    
       # geocoding service (see below for supported options):
       :lookup => :yandex,
-
+    
       # IP address geocoding service (see below for supported options):
       :ip_lookup => :maxmind,
-
+    
       # to use an API key:
       :api_key => "...",
-
+    
       # geocoding service request timeout, in seconds (default 3):
       :timeout => 5,
-
+    
       # set default units to kilometers:
       :units => :km,
-
+    
       # caching (see below for details):
       :cache => Redis.new,
       :cache_prefix => "..."
-
+    
     )
 
 Please see `lib/geocoder/configuration.rb` for a complete list of configuration options. Additionally, some lookups have their own configuration options, some of which are directly supported by Geocoder. For example, to specify a value for Google's `bounds` parameter:
@@ -375,21 +375,21 @@ You can also configure multiple geocoding services at once, like this:
 
       :timeout => 2,
       :cache => Redis.new,
-
+    
       :yandex => {
         :api_key => "...",
         :timeout => 5
       },
-
+    
       :baidu => {
         :api_key => "..."
       },
-
+    
       :maxmind => {
         :api_key => "...",
         :service => :omni
       }
-
+    
     )
 
 The above combines global and service-specific options and could be useful if you specify different geocoding services for different models or under different conditions. Lookup-specific settings override global settings. In the above example, the timeout for all lookups would be 2 seconds, except for Yandex which would be 5.
@@ -713,6 +713,18 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string
 * **Terms of Service**: https://adresse.data.gouv.fr/faq/ (in french)
 * **Limitations**: [Data licensed under Open Database License (ODbL) (you must provide attribution).](http://openstreetmap.fr/ban)
 
+#### AMap (`:amap`)
+
+- **API key**: required
+- **Quota**: 2000/day and 2000/minute for personal developer, 4000000/day and 60000/minute for enterprise developer, for geocoding requests
+- **Region**: China
+- **SSL support**: yes
+- **Languages**: Chinese (Simplified)
+- **Documentation**: http://lbs.amap.com/api/webservice/guide/api/georegeo
+- **Terms of Service**: http://lbs.amap.com/home/terms/
+- **Limitations**: Only good for non-commercial use. For commercial usage please check http://lbs.amap.com/home/terms/
+- **Notes**: To use AMap set `Geocoder.configure(:lookup => :amap, :api_key => "your_api_key")`.
+
 ### IP Address Services
 
 #### FreeGeoIP (`:freegeoip`)
@@ -835,7 +847,7 @@ You can generate ActiveRecord migrations and download and import data via provid
 
     # generate migration to create tables
     rails generate geocoder:maxmind:geolite_city
-
+    
     # download, unpack, and import data
     rake geocoder:maxmind:geolite:load PACKAGE=city
 
@@ -923,7 +935,7 @@ For example:
 
       # build an address from street, city, and state attributes
       geocoded_by :address_from_components
-
+    
       # store the fetched address in the full_address attribute
       reverse_geocoded_by :latitude, :longitude, :address => :full_address
     end
@@ -935,7 +947,7 @@ However, there can be only one set of latitude/longitude attributes, and whichev
       geocoded_by :address,
         :latitude  => :fetched_latitude,  # this will be overridden by the below
         :longitude => :fetched_longitude  # same here
-
+    
       reverse_geocoded_by :latitude, :longitude
     end
 
@@ -963,7 +975,7 @@ For example:
 
       after_validation :reverse_geocode, :if => :has_coordinates
       after_validation :geocode, :if => :has_location, :unless => :has_coordinates
-
+    
     end
 
 Use Outside of Rails
@@ -1193,7 +1205,7 @@ Instead of using `includes` to reduce the number of database queries, try using
     # Pass a :select option to the near scope to get the columns you want.
     # Instead of City.near(...).includes(:venues), try:
     City.near("Omaha, NE", 20, :select => "cities.*, venues.*").joins(:venues)
-
+    
     # This preload call will normally trigger two queries regardless of the
     # number of results; one query on hotels, and one query on administrators.
     # Instead of Hotel.near(...).includes(:administrator), try:
diff --git a/gemfiles/Gemfile.ruby1.9.3 b/gemfiles/Gemfile.ruby1.9.3
index 961e96fb12d77aa8570c6a14a873c7a291cba8dc..8726c30f5eb7aa83f937f7668a5ee704f28bcd8f 100644
--- a/gemfiles/Gemfile.ruby1.9.3
+++ b/gemfiles/Gemfile.ruby1.9.3
@@ -18,7 +18,7 @@ group :development, :test do
   gem 'test-unit' # install newer version with omit() method
 
   gem 'debugger'
-  gem 'webmock'
+  gem 'webmock', '~> 2.3.2'
 
   platforms :jruby do
     gem 'jruby-openssl'
diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb
index 04a6ef44b0cf39d4a903b35b70a95b90b32c8ac4..31e2b07081139dc3244d8f006d80bf6177a2d262 100644
--- a/lib/geocoder/lookup.rb
+++ b/lib/geocoder/lookup.rb
@@ -50,7 +50,8 @@ module Geocoder
         :geoportail_lu,
         :ban_data_gouv_fr,
         :test,
-        :latlon
+        :latlon,
+        :amap
       ]
     end
 
diff --git a/lib/geocoder/lookups/amap.rb b/lib/geocoder/lookups/amap.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6989f1bdc3871ec9af43f0cc100de0afd0f72791
--- /dev/null
+++ b/lib/geocoder/lookups/amap.rb
@@ -0,0 +1,59 @@
+require 'geocoder/lookups/base'
+require "geocoder/results/amap"
+
+module Geocoder::Lookup
+  class Amap < Base
+
+    def name
+      "AMap"
+    end
+
+    def required_api_key_parts
+      ["key"]
+    end
+
+    def query_url(query)
+      path = query.reverse_geocode? ? 'regeo' : 'geo'
+      "http://restapi.amap.com/v3/geocode/#{path}?" + url_query_string(query)
+    end
+
+    private # ---------------------------------------------------------------
+
+    def results(query, reverse = false)
+      return [] unless doc = fetch_data(query)
+      case [doc['status'], doc['info']]
+      when ['1', 'OK']
+        return doc['regeocodes'] unless doc['regeocodes'].blank?
+        return [doc['regeocode']] unless doc['regeocode'].blank?
+        return doc['geocodes'] unless doc['geocodes'].blank?
+      when ['0', 'INVALID_USER_KEY']
+        raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
+          warn("#{self.name} Geocoding API error: invalid api key.")
+      else
+        raise_error(Geocoder::Error, "server error.") ||
+          warn("#{self.name} Geocoding API error: server error - [#{doc['info']}]")
+      end
+      return []
+    end
+
+    def query_url_params(query)
+      params = {
+        :key => configuration.api_key,
+        :output => "json"
+      }
+      if query.reverse_geocode?
+        params[:location] = revert_coordinates(query.text)
+        params[:extensions] = "all"
+        params[:coordsys] = "gps"
+      else
+        params[:address] = query.sanitized_text
+      end
+      params.merge(super)
+    end
+
+    def revert_coordinates(text)
+      [text[1],text[0]].join(",")
+    end
+
+  end
+end
diff --git a/lib/geocoder/results/amap.rb b/lib/geocoder/results/amap.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1a526849a859fa530964444515ab8fd3bb590745
--- /dev/null
+++ b/lib/geocoder/results/amap.rb
@@ -0,0 +1,87 @@
+require 'geocoder/results/base'
+
+module Geocoder::Result
+  class Amap < Base
+
+    def coordinates
+      location = @data['location'] || @data['roadinters'].try(:first).try(:[], 'location') \
+        || address_components.try(:[], 'streetNumber').try(:[], 'location')
+      location.to_s.split(",").reverse.map(&:to_f)
+    end
+
+    def address
+      formatted_address
+    end
+
+    def state
+      province
+    end
+
+    def province
+      address_components['province']
+    end
+
+    def city
+      address_components['city'] == [] ? province : address_components["city"]
+    end
+
+    def district
+      address_components['district']
+    end
+
+    def street
+      if address_components["neighborhood"]["name"] != []
+        return address_components["neighborhood"]["name"]
+      elsif address_components['township'] != []
+        return address_components["township"]
+      else
+        return @data['street'] || address_components['streetNumber'].try(:[], 'street')
+      end
+    end
+
+    def street_number
+      @data['number'] || address_components['streetNumber'].try(:[], 'number')
+    end
+
+    def formatted_address
+      @data['formatted_address']
+    end
+
+    def address_components
+      @data['addressComponent'] || @data
+    end
+
+    def state_code
+      ""
+    end
+
+    def postal_code
+      ""
+    end
+
+    def country
+      "China"
+    end
+
+    def country_code
+      "CN"
+    end
+
+    ##
+    # Get address components of a given type. Valid types are defined in
+    # Baidu's Geocoding API documentation and include (among others):
+    #
+    #   :business
+    #   :cityCode
+    #
+    def self.response_attributes
+      %w[roads pois roadinters]
+    end
+
+    response_attributes.each do |a|
+      define_method a do
+        @data[a]
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/test/fixtures/amap_invalid_key b/test/fixtures/amap_invalid_key
new file mode 100644
index 0000000000000000000000000000000000000000..590b88b79752e702fb965f34b45b9c6f5536ce02
--- /dev/null
+++ b/test/fixtures/amap_invalid_key
@@ -0,0 +1 @@
+{"status":"0","info":"INVALID_USER_KEY","infocode":"10001"}
\ No newline at end of file
diff --git a/test/fixtures/amap_no_results b/test/fixtures/amap_no_results
new file mode 100644
index 0000000000000000000000000000000000000000..295f888776e14bee0064777144d337f9dde274b4
--- /dev/null
+++ b/test/fixtures/amap_no_results
@@ -0,0 +1,7 @@
+{
+  "status": "1",
+  "info": "OK",
+  "infocode": "10000",
+  "count": "0",
+  "geocodes": []
+}
\ No newline at end of file
diff --git a/test/fixtures/amap_reverse b/test/fixtures/amap_reverse
new file mode 100644
index 0000000000000000000000000000000000000000..6728ee849f6c27d4ac07286a840c4d986ede51cf
--- /dev/null
+++ b/test/fixtures/amap_reverse
@@ -0,0 +1,38 @@
+{
+  "status": "1",
+  "info": "OK",
+  "infocode": "10000",
+  "regeocode": {
+    "formatted_address": "Canada Ontario University Private ",
+    "addressComponent": {
+      "country": "Canada",
+      "province": "Ontario",
+      "city": [],
+      "citycode": [],
+      "district": [],
+      "adcode": [],
+      "township": "University Private",
+      "towncode": [],
+      "neighborhood": {
+        "name": [],
+        "type": []
+      },
+      "building": {
+        "name": [],
+        "type": []
+      },
+      "streetNumber": {
+        "street": "University Private",
+        "number": [],
+        "location": "-75.680763,45.426723",
+        "direction": [],
+        "distance": []
+      },
+      "businessAreas": []
+    },
+    "pois": [],
+    "roads": [],
+    "roadinters": [],
+    "aois": []
+  }
+}
\ No newline at end of file
diff --git a/test/fixtures/amap_shanghai_pearl_tower b/test/fixtures/amap_shanghai_pearl_tower
new file mode 100644
index 0000000000000000000000000000000000000000..7d153af61bfce42682a972fc059dd7988624ef66
--- /dev/null
+++ b/test/fixtures/amap_shanghai_pearl_tower
@@ -0,0 +1,29 @@
+{
+  "status": "1",
+  "info": "OK",
+  "infocode": "10000",
+  "count": "1",
+  "geocodes": [
+    {
+      "formatted_address": "上海市浦东新区明珠电视塔",
+      "province": "上海市",
+      "citycode": "021",
+      "city": "上海市",
+      "district": "浦东新区",
+      "township": [],
+      "neighborhood": {
+        "name": [],
+        "type": []
+      },
+      "building": {
+        "name": [],
+        "type": []
+      },
+      "adcode": "310115",
+      "street": [],
+      "number": [],
+      "location": "121.499567,31.239950",
+      "level": "兴趣点"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/test_helper.rb b/test/test_helper.rb
index abb3efa09726e8f78db1df3c6394b678ae3f553d..dfec77beb7b537c633e6df4e662e1f0a39a9854b 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -373,6 +373,13 @@ module Geocoder
       end
     end
 
+    require 'geocoder/lookups/amap'
+    class Amap
+      private
+      def default_fixture_filename
+        "amap_shanghai_pearl_tower"
+      end
+    end
 
   end
 end
diff --git a/test/unit/lookup_test.rb b/test/unit/lookup_test.rb
index 5a91ad573596da1fbf2a8acda5b3772ff882a721..4fa3a28daa49bb1e427f3e7e5548094f4201cb98 100644
--- a/test/unit/lookup_test.rb
+++ b/test/unit/lookup_test.rb
@@ -74,7 +74,7 @@ class LookupTest < GeocoderTestCase
   def test_raises_exception_on_invalid_key
     Geocoder.configure(:always_raise => [Geocoder::InvalidApiKey])
     #Geocoder::Lookup.all_services_except_test.each do |l|
-    [:bing, :yandex, :maxmind, :baidu, :baidu_ip].each do |l|
+    [:bing, :yandex, :maxmind, :baidu, :baidu_ip, :amap].each do |l|
       lookup = Geocoder::Lookup.get(l)
       assert_raises Geocoder::InvalidApiKey do
         lookup.send(:results, Geocoder::Query.new("invalid key"))
@@ -85,7 +85,7 @@ class LookupTest < GeocoderTestCase
   def test_returns_empty_array_on_invalid_key
     silence_warnings do
       #Geocoder::Lookup.all_services_except_test.each do |l|
-      [:bing, :yandex, :maxmind, :baidu, :baidu_ip].each do |l|
+      [:bing, :yandex, :maxmind, :baidu, :baidu_ip, :amap].each do |l|
         Geocoder.configure(:lookup => l)
         set_api_key!(l)
         assert_equal [], Geocoder.search("invalid key")
@@ -147,8 +147,14 @@ class LookupTest < GeocoderTestCase
     assert_match "token=MY_KEY", g.query_url(Geocoder::Query.new("232.65.123.94"))
   end
 
+  def test_amap_api_key
+    Geocoder.configure(:api_key => "MY_KEY")
+    g = Geocoder::Lookup::Amap.new
+    assert_match "key=MY_KEY", g.query_url(Geocoder::Query.new("202.198.16.3"))
+  end
+
   def test_raises_configuration_error_on_missing_key
-    [:bing, :baidu].each do |l|
+    [:bing, :baidu, :amap].each do |l|
       assert_raises Geocoder::ConfigurationError do
         Geocoder.configure(:lookup => l, :api_key => nil)
         Geocoder.search("Madison Square Garden, New York, NY  10001, United States")