I found that I was able to use the kmlstring parameter for the KMLLayer by subclassing the KMLLayer class and changing the internal esriRequest to use the kmlstring instead of the URL. This allows me to load KML files provided by the users. It required only replacing this one line in one internal function. I just place the kmlString (the url-escaped contents of the KML file) into the options object in the constructor.
define([
"dojo/_base/declare",
"dojo/_base/json",
"dojo/_base/lang",
"esri/request",
"esri/layers/KMLLayer"
], function ( declare, json, lang, esriRequest, KMLLayer) {
return declare(KMLLayer, {
_parseKml: function (map) {
var that = this;
this._fireUpdateStart();
this._io = esriRequest({
url: this.serviceUrl,
content: {
kmlString: this._options.kmlString,
model: "simple",
folders: "",
refresh: this.loaded ? !0 : void 0,
outSR: json.toJson(this._outSR.toJson())
},
callbackParamName: "callback",
load: function (response) {
that._io = null;
that._initLayer(response)
},
error: function (response) {
that._io = null;
var err = lang.mixin(Error(), response);
err.message = "Unable to load KML from text: " + that._options.kmlString + " " + (err.message || "");
that._fireUpdateEnd(err);
that.onError(err);
}
});
}
});
});